From 148b81e98a83985eb62821788e5de0520b932a67 Mon Sep 17 00:00:00 2001 From: M <149858635+mm9942@users.noreply.github.com> Date: Sat, 13 Apr 2024 00:07:08 +0200 Subject: [PATCH] reupload --- Cargo.toml | 31 ++ src/Advanced/mod.rs | 0 src/Core/KDF.rs | 418 +++++++++++++++++++++++++++ src/Core/cipher_aes.rs | 244 ++++++++++++++++ src/Core/cipher_xchacha.rs | 216 ++++++++++++++ src/Core/kyber/KeyKyber.rs | 288 ++++++++++++++++++ src/Core/kyber/kyber_crypto.rs | 335 +++++++++++++++++++++ src/Core/kyber/mod.rs | 266 +++++++++++++++++ src/Core/mod.rs | 64 ++++ src/KeyControl/file.rs | 166 +++++++++++ src/KeyControl/key.rs | 177 ++++++++++++ src/KeyControl/mod.rs | 134 +++++++++ src/cryptography/cryptographic.rs | 236 +++++++++++++++ src/cryptography/hmac_sign/mod.rs | 195 +++++++++++++ src/cryptography/hmac_sign/sign.rs | 139 +++++++++ src/cryptography/mod.rs | 150 ++++++++++ src/error.rs | 151 ++++++++++ src/lib.rs | 93 ++++++ src/log.rs | 91 ++++++ src/tests/KyberKeyTest.rs | 160 ++++++++++ src/tests/LoggingTests.rs | 58 ++++ src/tests/SignatureTests.rs | 175 +++++++++++ src/tests/kyber_tests.rs | 450 +++++++++++++++++++++++++++++ src/tests/mod.rs | 20 ++ 24 files changed, 4257 insertions(+) create mode 100644 Cargo.toml create mode 100644 src/Advanced/mod.rs create mode 100644 src/Core/KDF.rs create mode 100644 src/Core/cipher_aes.rs create mode 100644 src/Core/cipher_xchacha.rs create mode 100644 src/Core/kyber/KeyKyber.rs create mode 100644 src/Core/kyber/kyber_crypto.rs create mode 100644 src/Core/kyber/mod.rs create mode 100644 src/Core/mod.rs create mode 100644 src/KeyControl/file.rs create mode 100644 src/KeyControl/key.rs create mode 100644 src/KeyControl/mod.rs create mode 100644 src/cryptography/cryptographic.rs create mode 100644 src/cryptography/hmac_sign/mod.rs create mode 100644 src/cryptography/hmac_sign/sign.rs create mode 100644 src/cryptography/mod.rs create mode 100644 src/error.rs create mode 100644 src/lib.rs create mode 100644 src/log.rs create mode 100644 src/tests/KyberKeyTest.rs create mode 100644 src/tests/LoggingTests.rs create mode 100644 src/tests/SignatureTests.rs create mode 100644 src/tests/kyber_tests.rs create mode 100644 src/tests/mod.rs diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..01fcab8 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,31 @@ +[package] +name = "crypt_guard" +version = "1.1.8" +edition = "2021" +description = "CryptGuardLib is a comprehensive Rust library designed for strong encryption and decryption, incorporating post-quantum cryptography to safeguard against quantum threats. It's geared towards developers who need to embed advanced cryptographic capabilities in their Rust applications." +license = "MIT" +repository = "https://github.com/mm9942/CryptGuardLib" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +aes = "0.8.3" +env = "0.0.0" +hex = "0.4.3" +hmac = "0.12.1" +pqcrypto-falcon = { version = "0.3.0" } +pqcrypto-traits = "0.3.5" +rand = "0.8.5" +sha2 = "0.10.8" +tokio = { version = "1.35.1", features = ["full"], optional = true } +chacha20 = "0.9.1" +pqcrypto-dilithium = "0.5.0" +pqcrypto-kyber = "0.8.1" +chrono = "0.4.37" +lazy_static = "1.4.0" + +[dev-dependencies] +tempfile = "3.10.1" + +[features] +tokio = ["dep:tokio"] diff --git a/src/Advanced/mod.rs b/src/Advanced/mod.rs new file mode 100644 index 0000000..e69de29 diff --git a/src/Core/KDF.rs b/src/Core/KDF.rs new file mode 100644 index 0000000..22f9b7f --- /dev/null +++ b/src/Core/KDF.rs @@ -0,0 +1,418 @@ +use hmac::{Hmac, Mac}; +use sha2::{Sha512, Sha256}; +use pqcrypto_falcon::{falcon1024, falcon512}; +use pqcrypto_dilithium::{dilithium2, dilithium3, dilithium5}; +use std::{ + path::{PathBuf, Path}, + collections::HashMap, + marker::PhantomData, + result::Result, + io::{Read, Write}, + fs, +}; +use pqcrypto_traits::sign::{PublicKey, SecretKey, SignedMessage, DetachedSignature}; +use crate::{ + error::SigningErr, + log_activity, + LOGGER, +}; + +/// Represents the type of key used in cryptographic operations. +pub enum KeyVariant { + Public, + Secret, +} + +/// Defines the necessary functions for signing and verifying messages. +pub trait SignatureFunctions { + /// Signs a given message with the provided key. + fn sign_message(data: Vec, key: Vec) -> Result, SigningErr>; + /// Creates a detached signature for the given data. + fn detached_signature(data: Vec, key: Vec) -> Result, SigningErr>; + + /// Opens (or verifies) a signed message with the provided key. + fn open_message(signed_data: Vec, key: Vec) -> Result, SigningErr>; + /// Verifies a signature against the provided data and key. + fn verify(signature: Vec, data: Vec, key: Vec) -> Result; +} + + +/// Defines operations for key pair generation. +pub trait KeyOperations { + /// Generates a public and secret key pair. + fn keypair() -> Result<(Vec, Vec), SigningErr>; +} + +/// Implements Falcon1024 algorithm operations. +pub struct Falcon1024; +impl KeyOperations for Falcon1024 { + /// Generates a Falcon1024 key pair. + fn keypair() -> Result<(Vec, Vec), SigningErr> { + let (public_key, secret_key) = falcon1024::keypair(); + Ok((public_key.as_bytes().to_owned(), secret_key.as_bytes().to_owned())) + } +} +impl SignatureFunctions for Falcon1024 { + /// Signs a given message with the provided key. + fn sign_message(data: Vec, key: Vec) -> Result, SigningErr> { + log_activity!("Starting with signing of the message.", "\nUsed key: Falcon1024"); + let key = falcon1024::SecretKey::from_bytes(&key).unwrap(); + let signature = falcon1024::sign(&data, &key).as_bytes().to_owned(); + log_activity!("Completed signing the message.", "\nUsed key: Falcon1024"); + Ok(signature) + } + /// Creates a detached signature for the given data. + fn detached_signature(data: Vec, key: Vec) -> Result, SigningErr> { + log_activity!("Generating a detached signature from the specified data.", "\nUsed key: Falcon1024"); + let key = falcon1024::SecretKey::from_bytes(&key).unwrap(); + let signature = falcon1024::detached_sign(&data, &key).as_bytes().to_owned(); + log_activity!("Completed signing the message.", "\nUsed key: Falcon1024"); + Ok(signature) + } + /// Opens (or verifies) a signed message with the provided key. + fn open_message(signed_data: Vec, key: Vec) -> Result, SigningErr> { + log_activity!("Starting with signing of the message.", "\nUsed key: Falcon1024"); + let key = falcon1024::PublicKey::from_bytes(&key).unwrap(); + let signed_message = falcon1024::SignedMessage::from_bytes(&signed_data).unwrap(); + log_activity!("Completed signing the message.", "\nUsed key: Falcon1024"); + Ok(falcon1024::open(&signed_message, &key).unwrap()) + } + /// Verifies a signature against the provided data and key. + fn verify(signature: Vec, data: Vec, key: Vec) -> Result { + log_activity!("Starting verification of signed message.", "\nUsed key: Falcon1024"); + let key = falcon1024::PublicKey::from_bytes(&key).unwrap(); + let ds = falcon1024::DetachedSignature::from_bytes(&signature).unwrap(); + + let data = falcon1024::verify_detached_signature(&ds, &data, &key) + .map(|_| true) + .map_err(|_| SigningErr::SignatureVerificationFailed)?; + match &data { + true => log_activity!("Verification completed.", "\nUsed key: Falcon1024"), + false => log_activity!("Verification failed! Please use for more infos: RUST_BACKTRACE=[1 or full]", "\nUsed key: Falcon1024"), + }; + Ok( + data + ) + } +} + +pub struct Falcon512; +impl KeyOperations for Falcon512 { + /// Generates a Falcon512 key pair. + fn keypair() -> Result<(Vec, Vec), SigningErr> { + let (public_key, secret_key) = falcon512::keypair(); + Ok((public_key.as_bytes().to_owned(), secret_key.as_bytes().to_owned())) + } +} +impl SignatureFunctions for Falcon512 { + /// Signs a given message with the provided key. + fn sign_message(data: Vec, key: Vec) -> Result, SigningErr> { + log_activity!("Starting with signing of the message.", "\nUsed key: Falcon512"); + let key = falcon512::SecretKey::from_bytes(&key).unwrap(); + let signature = falcon512::sign(&data, &key).as_bytes().to_owned(); + log_activity!("Completed signing the message.", "\nUsed key: Falcon512"); + Ok(signature) + } + /// Creates a detached signature for the given data. + fn detached_signature(data: Vec, key: Vec) -> Result, SigningErr> { + log_activity!("Generating a detached signature from the specified data.", "\nUsed key: Falcon512"); + let key = falcon512::SecretKey::from_bytes(&key).unwrap(); + let signature = falcon512::detached_sign(&data, &key).as_bytes().to_owned(); + log_activity!("Completed signing the message.", "\nUsed key: Falcon512"); + Ok(signature) + } + /// Opens (or verifies) a signed message with the provided key. + fn open_message(signed_data: Vec, key: Vec) -> Result, SigningErr> { + log_activity!("Starting with signing of the message.", "\nSelected KDF: Falcon512"); + let key = falcon512::PublicKey::from_bytes(&key).unwrap(); + let signed_message = falcon512::SignedMessage::from_bytes(&signed_data).unwrap(); + log_activity!("Completed signing the message.", "\nSelected KDF: Falcon512"); + Ok(falcon512::open(&signed_message, &key).unwrap()) + } + /// Verifies a signature against the provided data and key. + fn verify(signature: Vec, data: Vec, key: Vec) -> Result { + log_activity!("Starting verification of signed message.", "\nSelected KDF: Falcon512"); + let key = falcon512::PublicKey::from_bytes(&key).unwrap(); + let ds = falcon512::DetachedSignature::from_bytes(&signature).unwrap(); + + let data = falcon512::verify_detached_signature(&ds, &data, &key) + .map(|_| true) + .map_err(|_| SigningErr::SignatureVerificationFailed)?; + match &data { + true => log_activity!("Verification completed.", "\nSelected KDF: Falcon512"), + false => log_activity!("Verification failed! Please use for more infos: RUST_BACKTRACE=[1 or full]", "\nSelected KDF: Falcon512"), + }; + Ok( + data + ) + } +} + + +pub struct Dilithium2; +impl KeyOperations for Dilithium2 { + /// Generates a Dilithium2 key pair. + fn keypair() -> Result<(Vec, Vec), SigningErr> { + let (public_key, secret_key) = dilithium2::keypair(); + Ok((public_key.as_bytes().to_owned(), secret_key.as_bytes().to_owned())) + } +} +impl SignatureFunctions for Dilithium2 { + /// Signs a given message with the provided key. + fn sign_message(data: Vec, key: Vec) -> Result, SigningErr> { + log_activity!("Starting with signing of the message.", "\nSelected KDF: Dilithium2"); + let key = dilithium2::SecretKey::from_bytes(&key).unwrap(); + let signature = dilithium2::sign(&data, &key).as_bytes().to_owned(); + log_activity!("Completed signing the message.", "\nSelected KDF: Dilithium2"); + Ok(signature) + } + /// Creates a detached signature for the given data. + fn detached_signature(data: Vec, key: Vec) -> Result, SigningErr> { + log_activity!("Starting with signing of the message.", "\nSelected KDF: Dilithium2"); + let key = dilithium2::SecretKey::from_bytes(&key).unwrap(); + let signature = dilithium2::detached_sign(&data, &key).as_bytes().to_owned(); + log_activity!("Completed signing the message.", "\nSelected KDF: Dilithium2"); + Ok(signature) + } + /// Opens (or verifies) a signed message with the provided key. + fn open_message(signed_data: Vec, key: Vec) -> Result, SigningErr> { + log_activity!("Starting with signing of the message.", "\nSelected KDF: Dilithium2"); + let key = dilithium2::PublicKey::from_bytes(&key).unwrap(); + let signed_message = dilithium2::SignedMessage::from_bytes(&signed_data).unwrap(); + log_activity!("Completed signing the message.", "\nSelected KDF: Dilithium2"); + Ok(dilithium2::open(&signed_message, &key).unwrap()) + } + /// Verifies a signature against the provided data and key. + fn verify(signature: Vec, data: Vec, key: Vec) -> Result { + log_activity!("Starting verification of signed message.", "\nSelected KDF: Dilithium2"); + let key = dilithium2::PublicKey::from_bytes(&key).unwrap(); + let ds = dilithium2::DetachedSignature::from_bytes(&signature).unwrap(); + + let data = dilithium2::verify_detached_signature(&ds, &data, &key) + .map(|_| true) + .map_err(|_| SigningErr::SignatureVerificationFailed)?; + match &data { + true => log_activity!("Verification completed.", "\nSelected KDF: Dilithiu2"), + false => log_activity!("Verification failed! Please use for more infos: RUST_BACKTRACE=[1 or full]", "\nSelected KDF: Dilithium2"), + }; + Ok( + data + ) + } +} + +pub struct Dilithium3; +impl KeyOperations for Dilithium3 { + /// Generates a Dilithium3 key pair. + fn keypair() -> Result<(Vec, Vec), SigningErr> { + let (public_key, secret_key) = dilithium3::keypair(); + Ok((public_key.as_bytes().to_owned(), secret_key.as_bytes().to_owned())) + } +} +impl SignatureFunctions for Dilithium3 { + /// Signs a given message with the provided key. + fn sign_message(data: Vec, key: Vec) -> Result, SigningErr> { + log_activity!("Starting with signing of the message.", "\nUsed key: Dilithium3"); + let key = dilithium3::SecretKey::from_bytes(&key).unwrap(); + let signature = dilithium3::sign(&data, &key).as_bytes().to_owned(); + log_activity!("Completed signing the message.", "\nUsed key: Dilithium3"); + Ok(signature) + } + /// Creates a detached signature for the given data. + fn detached_signature(data: Vec, key: Vec) -> Result, SigningErr> { + log_activity!("Starting with signing of the message.", "\nUsed key: Dilithium3"); + let key = dilithium3::SecretKey::from_bytes(&key).unwrap(); + let signature = dilithium3::detached_sign(&data, &key).as_bytes().to_owned(); + log_activity!("Completed signing the message.", "\nUsed key: Dilithium3"); + Ok(signature) + } + /// Opens (or verifies) a signed message with the provided key. + fn open_message(signed_data: Vec, key: Vec) -> Result, SigningErr> { + + log_activity!("Starting with signing of the message.", "\nUsed key: Dilithium3"); + let key = dilithium3::PublicKey::from_bytes(&key).unwrap(); + let signed_message = dilithium3::SignedMessage::from_bytes(&signed_data).unwrap(); + log_activity!("Completed signing the message.", "\nUsed key: Dilithium3"); + + Ok(dilithium3::open(&signed_message, &key).unwrap()) + } + /// Verifies a signature against the provided data and key. + fn verify(signature: Vec, data: Vec, key: Vec) -> Result { + log_activity!("Starting verification of signed message.", "\nUsed key: Dilithium3"); + let key = dilithium3::PublicKey::from_bytes(&key).unwrap(); + let ds = dilithium3::DetachedSignature::from_bytes(&signature).unwrap(); + + let data = dilithium3::verify_detached_signature(&ds, &data, &key) + .map(|_| true) + .map_err(|_| SigningErr::SignatureVerificationFailed)?; + match &data { + true => log_activity!("Verification completed.", "\nUsed key: Dilithium3"), + false => log_activity!("Verification failed! Please use for more infos: RUST_BACKTRACE=[1 or full]", "\nUsed key: Dilithium3"), + }; + Ok( + data + ) + } +} + +pub struct Dilithium5; +impl KeyOperations for Dilithium5 { + /// Generates a Dilithium5 key pair. + fn keypair() -> Result<(Vec, Vec), SigningErr> { + let (public_key, secret_key) = dilithium5::keypair(); + Ok((public_key.as_bytes().to_owned(), secret_key.as_bytes().to_owned())) + } +} +impl SignatureFunctions for Dilithium5 { + /// Signs a given message with the provided key. + fn sign_message(data: Vec, key: Vec) -> Result, SigningErr> { + log_activity!("Starting with signing of the message.", "\nUsed key: Dilithium5"); + let key = dilithium5::SecretKey::from_bytes(&key).unwrap(); + let signature = dilithium5::sign(&data, &key).as_bytes().to_owned(); + log_activity!("Completed signing the message.", "\nUsed key: Dilithium5"); + Ok(signature) + } + /// Creates a detached signature for the given data. + fn detached_signature(data: Vec, key: Vec) -> Result, SigningErr> { + log_activity!("Starting with signing of the message.", "\nUsed key: Dilithium5"); + let key = dilithium5::SecretKey::from_bytes(&key).unwrap(); + let signature = dilithium5::detached_sign(&data, &key).as_bytes().to_owned(); + log_activity!("Completed signing the message.", "\nUsed key: Dilithium5"); + Ok(signature) + } + /// Opens (or verifies) a signed message with the provided key. + fn open_message(signed_data: Vec, key: Vec) -> Result, SigningErr> { + log_activity!("Starting with signing of the message.", "\nUsed key: Dilithium5"); + let key = dilithium5::PublicKey::from_bytes(&key).unwrap(); + let signed_message = dilithium5::SignedMessage::from_bytes(&signed_data).unwrap(); + log_activity!("Completed signing the message.", "\nUsed key: Dilithium5"); + Ok(dilithium5::open(&signed_message, &key).unwrap()) + } + /// Verifies a signature against the provided data and key. + fn verify(signature: Vec, data: Vec, key: Vec) -> Result { + log_activity!("Starting verification of signed message.", "\nUsed key: Dilithium5"); + let key = dilithium5::PublicKey::from_bytes(&key).unwrap(); + let ds = dilithium5::DetachedSignature::from_bytes(&signature).unwrap(); + + let data = dilithium5::verify_detached_signature(&ds, &data, &key) + .map(|_| true) + .map_err(|_| SigningErr::SignatureVerificationFailed)?; + match &data { + true => log_activity!("Verification completed.", "\nUsed key: Dilithium5"), + false => log_activity!("Verification failed! Please use for more infos: RUST_BACKTRACE=[1 or full]", "\nUsed key: Dilithium5"), + }; + Ok( + data + ) + } +} + +pub struct Detached; +pub struct Message; + + +pub struct Signature { + algorithm: PhantomData, + signature_type: PhantomData, +} + +impl Signature { + pub fn new() -> Self { + Signature { algorithm: PhantomData, signature_type: PhantomData } + } +} + +// Implementation of Signature for Falcon1024 +impl Signature { + pub fn signature(&self, data: Vec, key: Vec) -> Result, SigningErr> { + Ok(Falcon1024::sign_message(data, key)?) + } + pub fn open(&self, signed_data: Vec, key: Vec) -> Result, SigningErr> { + Ok(Falcon1024::open_message(signed_data, key)?) + } +} + +impl Signature { + pub fn signature(&self, data: Vec, key: Vec) -> Result, SigningErr> { + Ok(Falcon1024::detached_signature(data, key)?) + } + pub fn verify(&self, data: Vec, signature: Vec, key: Vec) -> Result { + Ok(Falcon1024::verify(signature, data, key)?) + } +} + +// Implementation of Signature for Falcon512 +impl Signature { + pub fn signature(&self, data: Vec, key: Vec) -> Result, SigningErr> { + Ok(Falcon512::sign_message(data, key)?) + } + pub fn open(&self, signed_data: Vec, key: Vec) -> Result, SigningErr> { + Ok(Falcon512::open_message(signed_data, key)?) + } +} + +impl Signature { + pub fn signature(&self, data: Vec, key: Vec) -> Result, SigningErr> { + Ok(Falcon512::detached_signature(data, key)?) + } + pub fn verify(&self, data: Vec, signature: Vec, key: Vec) -> Result { + Ok(Falcon512::verify(signature, data, key)?) + } +} + +// Implementation of Signature for Dilithium2 +impl Signature { + pub fn signature(&self, data: Vec, key: Vec) -> Result, SigningErr> { + Ok(Dilithium2::sign_message(data, key)?) + } + pub fn open(&self, signed_data: Vec, key: Vec) -> Result, SigningErr> { + Ok(Dilithium2::open_message(signed_data, key)?) + } +} + +impl Signature { + pub fn signature(&self, data: Vec, key: Vec) -> Result, SigningErr> { + Ok(Dilithium2::detached_signature(data, key)?) + } + pub fn verify(&self, data: Vec, signature: Vec, key: Vec) -> Result { + Ok(Dilithium2::verify(signature, data, key)?) + } +} + +// Implementation of Signature for Dilithium3 +impl Signature { + pub fn signature(&self, data: Vec, key: Vec) -> Result, SigningErr> { + Ok(Dilithium3::sign_message(data, key)?) + } + pub fn open(&self, signed_data: Vec, key: Vec) -> Result, SigningErr> { + Ok(Dilithium3::open_message(signed_data, key)?) + } +} + +impl Signature { + pub fn signature(&self, data: Vec, key: Vec) -> Result, SigningErr> { + Ok(Dilithium3::detached_signature(data, key)?) + } + pub fn verify(&self, data: Vec, signature: Vec, key: Vec) -> Result { + Ok(Dilithium3::verify(signature, data, key)?) + } +} + +// Implementation of Signature for Dilithium5 +impl Signature { + pub fn signature(&self, data: Vec, key: Vec) -> Result, SigningErr> { + Ok(Dilithium5::sign_message(data, key)?) + } + pub fn open(&self, signed_data: Vec, key: Vec) -> Result, SigningErr> { + Ok(Dilithium5::open_message(signed_data, key)?) + } +} + +impl Signature { + pub fn signature(&self, data: Vec, key: Vec) -> Result, SigningErr> { + Ok(Dilithium5::detached_signature(data, key)?) + } + pub fn verify(&self, data: Vec, signature: Vec, key: Vec) -> Result { + Ok(Dilithium5::verify(signature, data, key)?) + } +} \ No newline at end of file diff --git a/src/Core/cipher_aes.rs b/src/Core/cipher_aes.rs new file mode 100644 index 0000000..d08765f --- /dev/null +++ b/src/Core/cipher_aes.rs @@ -0,0 +1,244 @@ +use crate::{ + *, + error::CryptError, + hmac_sign::*, + Core::{ + CryptographicFunctions, + KeyControl, + KeyControKyber512, + KeyControKyber768, + KeyControKyber1024, + KyberKeyFunctions, + kyber::KyberSizeVariant, + KeyControlVariant, + } +}; +use aes::{ + cipher::{ + BlockEncrypt, + BlockDecrypt, + generic_array::GenericArray, + KeyInit + }, + Aes256 +}; +use std::{ + path::{PathBuf, Path}, + marker::PhantomData, + result::Result, + io::{Read, Write}, + fs +}; +use pqcrypto_traits::kem::{PublicKey as PublicKeyKem, SecretKey as SecKeyKem, SharedSecret as SharedSecretKem, Ciphertext as CiphertextKem}; +use pqcrypto_kyber::kyber1024; +use pqcrypto_kyber::kyber1024::*; + +/// Provides AES encryption functionality, handling cryptographic information and shared secrets. +impl CipherAES { + /// Initializes a new `CipherAES` instance with the provided cryptographic information. + /// + /// # Parameters + /// - `infos`: Cryptographic information detailing the encryption or decryption process, content type, and more. + /// + /// # Returns + /// A new instance of `CipherAES`. + pub fn new(infos: CryptographicInformation) -> Self { + CipherAES { infos, sharedsecret: Vec::new() } + } + + /// Retrieves the current data intended for encryption or decryption. + /// + /// # Returns + /// The data as a vector of bytes (`Vec`) or a `CryptError` if the content cannot be accessed. + pub fn get_data(&self) -> Result, CryptError> { + let data = &self.infos.content()?; + let mut data = data.to_vec(); + Ok(data) + } + + /// Sets the shared secret key used for AES encryption and decryption. + /// + /// # Parameters + /// - `sharedsecret`: The shared secret as a byte vector. + /// + /// # Returns + /// A mutable reference to the `CipherAES` instance, allowing for chaining of operations. + pub fn set_shared_secret(&mut self, sharedsecret: Vec) -> &Self { + self.sharedsecret = sharedsecret; + self + } + + /// Retrieves the shared secret key. + /// + /// # Returns + /// A reference to the shared secret as a byte vector or a `CryptError` if it cannot be accessed. + pub fn sharedsecret(&self) -> Result<&Vec, CryptError> { + Ok(&self.sharedsecret) + } + + /// Retrieves the shared secret key. + /// + /// # Returns + /// A reference to the shared secret as a byte vector or a `CryptError` if it cannot be accessed. + fn encryption(&mut self) -> Result, CryptError> { + let file_contained = self.infos.contains_file()?; + if file_contained && self.infos.metadata.content_type == ContentType::File { + self.infos.content = fs::read(self.infos.location()?).unwrap(); + } + let encrypted_data = self.encrypt_aes()?; + println!("Encrypted Data: {:?}", encrypted_data); + + let mut passphrase = self.infos.passphrase()?.to_vec(); + let mut hmac = Sign::new(encrypted_data, passphrase, Operation::Sign, SignType::Sha512); + let data = hmac.hmac(); + if self.infos.safe()? { + let _ = self.infos.set_data(&data)?; + let _ = self.infos.safe_file()?; + } + Ok(data) + } + + /// Saves the ciphertext to a file specified within the cryptographic information's location. + /// + /// # Parameters + /// - `encrypted_data`: The ciphertext to be saved. + /// + /// # Returns + /// An `Ok(())` upon successful save or a `CryptError` if saving fails. + fn save_ciphertext(&self, encrypted_data: &[u8]) -> Result<(), CryptError> { + use std::{fs::File, io::Write}; + + if let Some(file_metadata) = &self.infos.location { + let file_path = file_metadata.parent()?; + let filename = format!("{}/ciphertext.pem", file_path.as_os_str().to_str().unwrap()); + let file_path_with_enc = PathBuf::from(filename); + + let mut buffer = File::create(file_path_with_enc).map_err(|_| CryptError::WriteError)?; + buffer.write_all(self.sharedsecret()?).map_err(|_| CryptError::WriteError)?; + + Ok(()) + } else { + Err(CryptError::PathError) + } + } + + /// Encrypts the provided data with AES-256. + /// + /// # Returns + /// A result containing the encrypted data as a byte vector or a `CryptError` if encryption fails. + fn encrypt_aes(&mut self) -> Result, CryptError> { + let block_size = 16; + let mut padded_data = self.get_data()?; + + // Padding the data if necessary + let padding_needed = block_size - (padded_data.len() % block_size); + padded_data.extend(vec![padding_needed as u8; padding_needed]); + + let mut encrypted_data = vec![0u8; padded_data.len()]; + let sharedsecret = self.sharedsecret()?; + let cipher = Aes256::new(GenericArray::from_slice(sharedsecret)); + + for (chunk, encrypted_chunk) in padded_data.chunks(block_size).zip(encrypted_data.chunks_mut(block_size)) { + let mut block = GenericArray::clone_from_slice(chunk); + cipher.encrypt_block(&mut block); + encrypted_chunk.copy_from_slice(&block); + } + + Ok(encrypted_data) + } + + /// Decrypts data using AES-256. + /// + /// # Returns + /// The decrypted data as a byte vector or a `CryptError` if decryption fails. + fn decryption(&mut self) -> Result, CryptError> { + let file_contained = self.infos.contains_file()?; + if file_contained && self.infos.metadata.content_type == ContentType::File { + self.infos.content = fs::read(self.infos.location()?).unwrap(); + + } + + let encrypted_data_with_hmac = self.infos.content()?.to_vec(); + let passphrase = self.infos.passphrase()?.to_vec(); + println!("Data Length: {}", encrypted_data_with_hmac.len()); + + let mut verifier = Sign::new(encrypted_data_with_hmac, passphrase, Operation::Verify, SignType::Sha512); + let verified_data = verifier.hmac(); + + self.infos.set_data(&verified_data)?; + //println!("{:?}", verified_data); + let data = self.decrypt_aes()?; + if self.infos.safe()? { + let _ = self.infos.set_data(&data)?; + let _ = self.infos.safe_file()?; + } + println!("Decrypted Data: {:?}", data); + Ok(data) + } + + /// Decrypts the provided data with AES-256. + /// + /// # Returns + /// A result containing the decrypted data as a byte vector or a `CryptError` if decryption fails. + fn decrypt_aes(&mut self) -> Result, CryptError> { + let data = &self.infos.content()?; + let block_size = 16; + + // Ensure the data length is a multiple of the block size + if data.len() % block_size != 0 { + return Err(CryptError::InvalidDataLength); + } + + let mut decrypted_data = vec![0u8; data.len()]; + let sharedsecret = self.sharedsecret()?; + let cipher = Aes256::new(GenericArray::from_slice(sharedsecret)); + + for (chunk, decrypted_chunk) in data.chunks(block_size).zip(decrypted_data.chunks_mut(block_size)) { + let mut block = GenericArray::clone_from_slice(chunk); + cipher.decrypt_block(&mut block); + decrypted_chunk.copy_from_slice(&block); + } + + if let Some(&padding_length) = decrypted_data.last() { + decrypted_data.truncate(decrypted_data.len() - padding_length as usize); + } + + Ok(decrypted_data) + } +} + + +impl CryptographicFunctions for CipherAES { + /// Performs the encryption process using a public key. + /// + /// # Parameters + /// - `public_key`: The public key for encryption. + /// + /// # Returns + /// A result containing the encrypted data and the ciphertext as a key, or a `CryptError`. + fn encrypt(&mut self, public_key: Vec) -> Result<(Vec, Vec), CryptError> { + let mut key = KeyControlVariant::new(self.infos.metadata.key_type()?); + let (sharedsecret, ciphertext) = key.encap(&public_key)?; + println!("Shared secret: {:?}\nLength: {}", sharedsecret, sharedsecret.len()); + let _ = self.set_shared_secret(sharedsecret); + + Ok((self.encryption()?, ciphertext)) + } + + /// Performs the decryption process using a secret key and ciphertext. + /// + /// # Parameters + /// - `secret_key`: The secret key for decryption. + /// - `ciphertext`: The ciphertext to decrypt. + /// + /// # Returns + /// The decrypted data as a byte vector or a `CryptError` if decryption fails. + fn decrypt(&mut self, secret_key: Vec, ciphertext: Vec) -> Result, CryptError>{ + let mut key = KeyControlVariant::new(self.infos.metadata.key_type()?); + let sharedsecret = key.decap(&secret_key, &ciphertext)?; + println!("shared secret: {:?}\nLength: {}", sharedsecret, sharedsecret.len()); + let _ = self.set_shared_secret(sharedsecret); + + Ok(self.decryption()?) + } +} diff --git a/src/Core/cipher_xchacha.rs b/src/Core/cipher_xchacha.rs new file mode 100644 index 0000000..147d650 --- /dev/null +++ b/src/Core/cipher_xchacha.rs @@ -0,0 +1,216 @@ +use crate::{ + *, + cryptography::*, + error::*, + hmac_sign::*, + Core::{ + CryptographicFunctions, + KeyControl, + KeyControKyber512, + KeyControKyber768, + KeyControKyber1024, + KyberKeyFunctions, + kyber::KyberSizeVariant, + KeyControlVariant, + } +}; +use pqcrypto_traits::kem::{PublicKey as PublicKeyKem, SecretKey as SecKeyKem, SharedSecret as SharedSecretKem, Ciphertext as CiphertextKem}; +use pqcrypto_kyber::kyber1024; +use pqcrypto_kyber::kyber1024::*; +use chacha20::{ + XChaCha20, + cipher::{KeyIvInit, StreamCipher, StreamCipherSeek, generic_array::GenericArray} +}; +use std::{ + iter::repeat, + path::{PathBuf, Path}, + marker::PhantomData, + result::Result, + io::{Read, Write}, + fs +}; +use rand::{RngCore, rngs::OsRng}; +use hex; + + +/// Generates a 24-byte nonce using OS-level randomness. +/// +/// # Returns +/// A 24-byte array filled with secure random bytes. +pub fn generate_nonce() -> [u8; 24] { + let mut nonce = [0u8; 24]; + OsRng.fill_bytes(&mut nonce); + nonce +} + +/// The main struct for handling cryptographic operations with ChaCha20 algorithm. +/// It encapsulates the cryptographic information, shared secret, and nonce required for encryption and decryption. +impl CipherChaCha { + /// Constructs a new `CipherChaCha` instance with specified cryptographic information and an optional nonce. + /// + /// # Parameters + /// - `infos`: Cryptographic information including content, passphrase, metadata, and location for encryption or decryption. + /// - `nonce`: Optional hexadecimal string representation of the nonce. If not provided, a nonce will be generated. + /// + /// # Returns + /// A new `CipherChaCha` instance. + pub fn new(infos: CryptographicInformation, nonce: Option) -> 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(), + }; + // println!("infos: {:?}", infos); + CipherChaCha { infos, sharedsecret: Vec::new(), nonce: nonce } + } + + /// Retrieves the encrypted or decrypted data stored within the `CryptographicInformation`. + /// + /// # Returns + /// A result containing the data as a vector of bytes (`Vec`) or a `CryptError`. + pub fn get_data(&self) -> Result, CryptError> { + let data = &self.infos.content()?; + let mut data = data.to_vec(); + + Ok(data) + } + /// Sets the shared secret for the cryptographic operation. + /// + /// # Parameters + /// - `sharedsecret`: A vector of bytes (`Vec`) representing the shared secret. + /// + /// # Returns + /// A reference to the `CipherChaCha` instance to allow method chaining. + pub fn set_shared_secret(&mut self, sharedsecret: Vec) -> &Self { + self.sharedsecret = sharedsecret; + self + } + + /// Retrieves the shared secret. + /// + /// # Returns + /// A result containing a slice of the shared secret (`&[u8]`) or a `CryptError`. + pub fn sharedsecret(&self) -> Result<&[u8], CryptError> { + Ok(&self.sharedsecret) + } + + /// Sets the nonce for cryptographic operations. + /// + /// # Parameters + /// - `nonce`: A 24-byte array representing the nonce. + /// + /// # Returns + /// A slice of the set nonce (`&[u8; 24]`). + pub fn set_nonce(&mut self, nonce: [u8; 24]) -> &[u8; 24] { + self.nonce = nonce; + &self.nonce + } + + /// Retrieves the nonce. + /// + /// # Returns + /// A slice of the current nonce (`&[u8; 24]`). + pub fn nonce(&self) -> &[u8; 24] { + &self.nonce + } + + /// Performs encryption or decryption based on the process type defined in `CryptographicInformation`. + /// + /// # Returns + /// A result containing a tuple of encrypted data (`Vec`) and the nonce vector (`Vec`) used, or a `CryptError`. + /// This method reads the file if `ContentType` is File and performs cryptographic operations accordingly. + fn cryptography(&mut self) -> Result<(Vec, Vec), 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)?; + } + + let mut encrypted_data: Vec = Vec::new(); + let mut nonce_vec: Vec = Vec::new(); + + let process_result = match self.infos.metadata.process()? { + Process::Encryption => { + let process_data_result = self.process_data()?; + encrypted_data = process_data_result.0; + nonce_vec = process_data_result.1; + + let mut hmac = Sign::new(encrypted_data, passphrase, Operation::Sign, SignType::Sha512); + let data = hmac.hmac(); + + if self.infos.safe()? { + let _ = self.infos.set_data(&data)?; + let _ = 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 process_data_result = self.process_data()?; + encrypted_data = process_data_result.0; + nonce_vec = process_data_result.1; + if self.infos.safe()? { + let _ = self.infos.set_data(&encrypted_data)?; + let _ = self.infos.safe_file()?; + } + Ok((encrypted_data, nonce_vec)) + }, + _ => Err(|e| CryptError::IOError(e)), + }; + let result = process_result.map_err(|_| CryptError::EncryptionFailed)?; + Ok(result) + } + + /// Helper function to perform the encryption or decryption process based on the current settings. + /// + /// # Returns + /// A result containing a tuple of processed data (`Vec`) and nonce vector (`Vec`), or a `CryptError`. + fn process_data(&self) -> Result<(Vec, Vec), 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())) + } +} + +impl CryptographicFunctions for CipherChaCha { + /// Encrypts the provided data using the public key. + /// + /// # Parameters + /// - `public_key`: The public key used for encryption. + /// + /// # Returns + /// A result containing a tuple of the encrypted data (`Vec`) and the key used, or a `CryptError`. + /// Additionally, prints a message to stdout with the nonce for user reference. + fn encrypt(&mut self, public_key: Vec) -> Result<(Vec, Vec), CryptError> { + let mut 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)) + } + + /// Decrypts the provided data using the secret key and ciphertext. + /// + /// # Parameters + /// - `secret_key`: The secret key used for decryption. + /// - `ciphertext`: The ciphertext to decrypt. + /// + /// # Returns + /// A result containing the decrypted data (`Vec`), or a `CryptError`. + fn decrypt(&mut self, secret_key: Vec, ciphertext: Vec) -> Result, CryptError>{ + let mut 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) + } +} \ No newline at end of file diff --git a/src/Core/kyber/KeyKyber.rs b/src/Core/kyber/KeyKyber.rs new file mode 100644 index 0000000..1cc26f7 --- /dev/null +++ b/src/Core/kyber/KeyKyber.rs @@ -0,0 +1,288 @@ +use super::*; + +/// Trait for implementing key management functions. This trait provides +/// an interface for key pair generation, encapsulation/decapsulation of secrets, +/// and key manipulation (such as setting and getting key values). +pub trait KyberKeyFunctions { + /// Generates a new key pair. + fn keypair() -> Result<(Vec, Vec), CryptError>; + /// Encapsulates a secret using a public key. + fn encap(public_key: &[u8]) -> Result<(Vec, Vec), CryptError>; + /// Decapsulates a secret using a secret key and a ciphertext. + fn decap(secret_key: &[u8], ciphertext: &[u8]) -> Result, CryptError>; +} +/// Implementation for Kyber 1024 variant. +pub struct KeyControKyber1024; +impl KyberKeyFunctions for KeyControKyber1024{ + /// Generates a public and secret key pair using the Kyber1024 algorithm. + fn keypair() -> Result<(Vec,Vec), CryptError> { + use pqcrypto_kyber::kyber1024::*; + log_activity!("Generating a new keypair.\n\tThe used KEM: ", format!("Kyber{}", 1024).as_str()); + + let (pk, sk) = keypair(); + let public_key = pk.as_bytes().to_owned(); + let secret_key = sk.as_bytes().to_owned(); + + log_activity!("A new keypair was created.\n\tThe used KEM: ", format!("Kyber{}", 1024).as_str()); + Ok((public_key, secret_key)) + } + + /// Encapsulates a secret using a public key to produce a shared secret and a ciphertext. + fn encap(public: &[u8]) -> Result<(Vec,Vec), CryptError> { + use pqcrypto_kyber::kyber1024::*; + log_activity!("Generating shared_secret and ciphertext.\n\tThe used KEM: ", format!("Kyber{}", 1024).as_str()); + + let pk = PublicKey::from_bytes(&public).unwrap(); + let (ss, ct) = encapsulate(&pk); + + let ciphertext = ct.as_bytes().to_vec(); + let shared_secret = ss.as_bytes().to_vec(); + + + log_activity!("Finished generating shared_secret and ciphertext.\n\tThe used KEM: ", format!("Kyber{}", 1024).as_str()); + Ok((shared_secret, ciphertext)) + } + + /// Decapsulates the ciphertext using a secret key to retrieve the shared secret. + fn decap(sec: &[u8], cipher: &[u8]) -> Result, CryptError> { + use pqcrypto_kyber::kyber1024::*; + log_activity!("Starting decapsulation of shared_secret using secret_key and ciphertext.\n\tThe used KEM: ", format!("Kyber{}", 1024).as_str()); + + let ct = Ciphertext::from_bytes(&cipher).unwrap(); + let sk = SecretKey::from_bytes(&sec).unwrap(); + let ss2 = decapsulate(&ct, &sk); + let shared_secret = ss2.as_bytes().to_vec(); + + log_activity!("Decapsulated the shared_secret using secret_key and ciphertext.\n\tThe used KEM: ", format!("Kyber{}", 1024).as_str()); + Ok(shared_secret) + } +} + +/// Implementation for Kyber 768 variant. +pub struct KeyControKyber768; +impl KyberKeyFunctions for KeyControKyber768 { + /// Generates a public and secret key pair using the Kyber768 algorithm. + fn keypair() -> Result<(Vec,Vec), CryptError> { + use pqcrypto_kyber::kyber768::*; + log_activity!("Generating a new keypair.\n\tThe used KEM: ", format!("Kyber{}", 768).as_str()); + + let (pk, sk) = keypair(); + let public_key = pk.as_bytes().to_vec(); + let secret_key = sk.as_bytes().to_vec(); + log_activity!("A new keypair was created.\n\tThe used KEM: ", format!("Kyber{}", 768).as_str()); + + Ok((public_key, secret_key)) + } + + /// Encapsulates a secret using a public key to produce a shared secret and a ciphertext. + fn encap(public: &[u8]) -> Result<(Vec,Vec), CryptError> { + use pqcrypto_kyber::kyber768::*; + log_activity!("Generating shared_secret and ciphertext.\n\tThe used KEM: ", format!("Kyber{}", 768).as_str()); + + let pk = PublicKey::from_bytes(&public).unwrap(); + let (ss, ct) = encapsulate(&pk); + + let ciphertext = ct.as_bytes().to_vec(); + let shared_secret = ss.as_bytes().to_vec(); + log_activity!("Finished generating shared_secret and ciphertext.\n\tThe used KEM: ", format!("Kyber{}", 768).as_str()); + + Ok((shared_secret, ciphertext)) + } + + /// Decapsulates the ciphertext using a secret key to retrieve the shared secret. + fn decap(sec: &[u8], cipher: &[u8]) -> Result, CryptError> { + use pqcrypto_kyber::kyber768::*; + log_activity!("Starting decapsulation of shared_secret using secret_key and ciphertext.\n\tThe used KEM: ", format!("Kyber{}", 768).as_str()); + + let ct = Ciphertext::from_bytes(&cipher).unwrap(); + let sk = SecretKey::from_bytes(&sec).unwrap(); + let ss2 = decapsulate(&ct, &sk); + let shared_secret = ss2.as_bytes().to_vec(); + log_activity!("Decapsulated the shared_secret using secret_key and ciphertext.\n\tThe used KEM: ", format!("Kyber{}", 768).as_str()); + + Ok(shared_secret) + } +} + +/// Implementation for Kyber 512 variant. +pub struct KeyControKyber512; +impl KyberKeyFunctions for KeyControKyber512 { + /// Generates a public and secret key pair using the Kyber512 algorithm. + fn keypair() -> Result<(Vec,Vec), CryptError> { + use pqcrypto_kyber::kyber512::*; + log_activity!("Generating a new keypair.\n\tThe used KEM: ", format!("Kyber{}", 512).as_str()); + + let (pk, sk) = keypair(); + let public_key = pk.as_bytes().to_vec(); + let secret_key = sk.as_bytes().to_vec(); + log_activity!("A new keypair was created.\n\tThe used KEM: ", format!("Kyber{}", 512).as_str()); + + Ok((public_key, secret_key)) + } + + /// Encapsulates a secret using a public key to produce a shared secret and a ciphertext. + fn encap(public: &[u8]) -> Result<(Vec,Vec), CryptError> { + use pqcrypto_kyber::kyber512::*; + log_activity!("Generating shared_secret and ciphertext.\n\tThe used KEM: ", format!("Kyber{}", 512).as_str()); + + let pk = PublicKey::from_bytes(&public).unwrap(); + let (ss, ct) = encapsulate(&pk); + + let ciphertext = ct.as_bytes().to_vec(); + let shared_secret = ss.as_bytes().to_vec(); + log_activity!("Finished generating shared_secret and ciphertext.\n\tThe used KEM: ", format!("Kyber{}", 512).as_str()); + + Ok((shared_secret, ciphertext)) + } + + /// Decapsulates the ciphertext using a secret key to retrieve the shared secret. + fn decap(sec: &[u8], cipher: &[u8]) -> Result, CryptError> { + use pqcrypto_kyber::kyber512::*; + log_activity!("Starting decapsulation of shared_secret using secret_key and ciphertext.\n\tThe used KEM: ", format!("Kyber{}", 512).as_str()); + + let ct = Ciphertext::from_bytes(&cipher).unwrap(); + let sk = SecretKey::from_bytes(&sec).unwrap(); + let ss2 = decapsulate(&ct, &sk); + let shared_secret = ss2.as_bytes().to_vec(); + log_activity!("Decapsulated the shared_secret using secret_key and ciphertext.\n\tThe used KEM: ", format!("Kyber{}", 512).as_str()); + + Ok(shared_secret) + } +} + +/// A structure to manage cryptographic keys and operations for the Kyber algorithm. +/// It encapsulates the public key, secret key, ciphertext, and shared secret. +pub struct KeyControl { + pub public_key: Vec, + pub secret_key: Vec, + pub ciphertext: Vec, + pub shared_secret: Vec, + _marker: std::marker::PhantomData, +} + +impl KeyControl { + /// Constructs a new instance of `KeyControl`. + pub fn new() -> Self { + KeyControl { + public_key: Vec::new(), + secret_key: Vec::new(), + ciphertext: Vec::new(), + shared_secret: Vec::new(), + _marker: PhantomData, + } + } + /// Sets the ciphertext for the `KeyControl` instance. + pub fn set_ciphertext(&mut self, cipher: Vec) -> Result<(), CryptError> { + Ok(self.ciphertext = cipher) + } + + /// Sets the public key for the `KeyControl` instance. + pub fn set_public_key(&mut self, public: Vec) -> Result<(), CryptError> { + Ok(self.public_key = public) + + } + + /// Sets the secret key for the `KeyControl` instance. + pub fn set_secret_key(&mut self, sec: Vec) -> Result<(), CryptError> { + Ok(self.secret_key = sec) + + } + + /// Retrieves a specified key based on `KeyTypes`. + pub fn get_key(&self, key: KeyTypes) -> Result { + let key = match key { + KeyTypes::None => unimplemented!(), + KeyTypes::PublicKey => { + Key::new(KeyTypes::PublicKey, self.public_key.to_vec()) + } + KeyTypes::SecretKey => { + Key::new(KeyTypes::SecretKey, self.secret_key.to_vec()) + } + KeyTypes::Ciphertext => { + Key::new(KeyTypes::Ciphertext, self.ciphertext.to_vec()) + } + KeyTypes::SharedSecret => { + Key::new(KeyTypes::SharedSecret, self.shared_secret.to_vec()) + } + }; + Ok(key) + } + + /// Saves a specified key to a file at the given base path. + pub fn save(&self, key: KeyTypes, base_path: PathBuf) -> Result<(), CryptError> { + let key = match key { + KeyTypes::None => unimplemented!(), + KeyTypes::PublicKey => { + Key::new(KeyTypes::PublicKey, self.public_key.to_vec()) + } + KeyTypes::SecretKey => { + Key::new(KeyTypes::SecretKey, self.secret_key.to_vec()) + } + KeyTypes::Ciphertext => { + Key::new(KeyTypes::Ciphertext, self.ciphertext.to_vec()) + } + KeyTypes::SharedSecret => unimplemented!(), + }; + key.save(base_path) + } + /// Loads a specified key from a file. + pub fn load(&self, key: KeyTypes, path: &Path) -> Result, CryptError> { + let key = match key { + KeyTypes::None => unimplemented!(), + KeyTypes::PublicKey => { + FileMetadata::from( + PathBuf::from(path), + FileTypes::PublicKey, + FileState::Other + ) + } + KeyTypes::SecretKey => { + FileMetadata::from( + PathBuf::from(path), + FileTypes::SecretKey, + FileState::Other + ) + } + KeyTypes::Ciphertext => { + FileMetadata::from( + PathBuf::from(path), + FileTypes::Ciphertext, + FileState::Other + ) + } + KeyTypes::SharedSecret => unimplemented!(), + }; + Ok(key.load().unwrap()) + } + + + /// Getter methods for public_key, secret_key, ciphertext, and shared_secret. + + pub fn public_key(&self) -> Result, CryptError> { + let key = &self.public_key; + Ok(key.to_vec()) + } + pub fn secret_key(&self) -> Result, CryptError> { + let key = &self.secret_key; + Ok(key.to_vec()) + } + pub fn ciphertext(&self) -> Result, CryptError> { + let key = &self.ciphertext; + Ok(key.to_vec()) + } + pub fn shared_secret(&self) -> Result, CryptError> { + let key = &self.shared_secret; + Ok(key.to_vec()) + } + + /// Encapsulates a secret using a public key. + pub fn encap(&self, public: &[u8]) -> Result<(Vec,Vec), CryptError> { + T::encap(public) + } + /// Decapsulates the ciphertext using a secret key to retrieve the shared secret. + pub fn decap(&self, secret_key: &[u8], ciphertext: &[u8]) -> Result, CryptError> { + // Call the `decap` method on the type `T` that `KeyControl` wraps around + T::decap(secret_key, ciphertext) + } + +} \ No newline at end of file diff --git a/src/Core/kyber/kyber_crypto.rs b/src/Core/kyber/kyber_crypto.rs new file mode 100644 index 0000000..44105ee --- /dev/null +++ b/src/Core/kyber/kyber_crypto.rs @@ -0,0 +1,335 @@ +use super::*; + +/// Provides Kyber encryption functions for AES algorithm. +impl KyberFunctions for Kyber +where + KyberSize: KyberSizeVariant, +{ + /// Encrypts a file with AES algorithm, given a path and a passphrase. + /// Returns the encrypted data and cipher. + fn encrypt_file(&mut self, path: PathBuf, passphrase: &str) -> Result<(Vec, Vec), CryptError> { + if !Path::new(&path).exists() { + log_activity!(format!("Error: {}.", CryptError::FileNotFound).as_str(), ""); + return Err(CryptError::FileNotFound); + } + + let (key_encap_mechanism, kybersize) = match KyberSize::variant() { + KyberVariant::Kyber512 => { + (KeyEncapMechanism::kyber512(), 512 as usize) + }, + KyberVariant::Kyber768 => { + (KeyEncapMechanism::kyber768(), 768 as usize) + }, + KyberVariant::Kyber1024 => { + (KeyEncapMechanism::kyber1024(), 1024 as usize) + }, + }; + let crypt_metadata = CryptographicMetadata::from( + Process::encryption(), + CryptographicMechanism::aes(), + key_encap_mechanism, + ContentType::file(), + ); + let file = FileMetadata::from(path, FileTypes::other(), FileState::not_encrypted()); + let infos = CryptographicInformation::from(Vec::new(), passphrase.as_bytes().to_vec(), crypt_metadata, true, Some(file)); + let mut aes = CipherAES::new(infos); + log_activity!("Creating a new cipher instance of AES.", ""); + + let (data, cipher) = aes.encrypt(self.kyber_data.key()?).unwrap(); + log_activity!("Finished:\n\t\tAlgorithm:\t\tAES,\n\t\tContent Type:\tFile\n\t\tProcess:\t\tEncryption\n\t\tKEM:\t\t\t", format!("Kyber{}", kybersize).as_str()); + + write_log!(); + Ok((data, cipher)) + } + /// Encrypts a message with AES algorithm, given the message and a passphrase. + /// Returns the encrypted data and cipher. + fn encrypt_msg(&mut self, message: &str, passphrase: &str) -> Result<(Vec, Vec), CryptError> { + let (key_encap_mechanism, kybersize) = match KyberSize::variant() { + KyberVariant::Kyber512 => { + (KeyEncapMechanism::kyber512(), 512 as usize) + }, + KyberVariant::Kyber768 => { + (KeyEncapMechanism::kyber768(), 768 as usize) + }, + KyberVariant::Kyber1024 => { + (KeyEncapMechanism::kyber1024(), 1024 as usize) + }, + }; + let crypt_metadata = CryptographicMetadata::from( + Process::encryption(), + CryptographicMechanism::aes(), + key_encap_mechanism, + ContentType::message(), + ); + let infos = CryptographicInformation::from(message.as_bytes().to_owned(), passphrase.as_bytes().to_vec(), crypt_metadata, false, None); + let mut aes = CipherAES::new(infos); + log_activity!("Creating a new cipher instance of AES.", ""); + + let (data, cipher) = aes.encrypt(self.kyber_data.key()?).unwrap(); + log_activity!("Finished:\n\t\tAlgorithm:\t\tAES,\n\t\tContent Type:\tMessage\n\t\tProcess:\t\tEncryption\n\t\tKEM:\t\t\t", format!("Kyber{}", kybersize).as_str()); + + write_log!(); + Ok((data, cipher)) + } + /// Placeholder for decrypt_file, indicating operation not allowed in encryption mode. + fn decrypt_file(&self, path: PathBuf, passphrase: &str, ciphertext: Vec) -> Result, CryptError> { + Err(CryptError::new("You're currently in the process state of encryption. Decryption of files isn't allowed!")) + } + /// Placeholder for decrypt_msg, indicating operation not allowed in encryption mode. + fn decrypt_msg(&self, message: Vec, passphrase: &str, ciphertext: Vec) -> Result, CryptError> { + Err(CryptError::new("You're currently in the process state of encryption. Decryption of messanges isn't allowed!")) + } +} + + +/// Provides Kyber decryption functions for AES algorithm. +impl KyberFunctions for Kyber +where + KyberSize: KyberSizeVariant, +{ + /// Placeholder for encrypt_file, indicating operation not allowed in decryption mode. + fn encrypt_file(&mut self, path: PathBuf, passphrase: &str) -> Result<(Vec, Vec), CryptError> { + Err(CryptError::new("You're currently in the process state of encryption. Decryption of files isn't allowed!")) + } + /// Placeholder for encrypt_msg, indicating operation not allowed in decryption mode. + fn encrypt_msg(&mut self, message: &str, passphrase: &str) -> Result<(Vec, Vec), CryptError> { + Err(CryptError::new("You're currently in the process state of encryption. Decryption of messanges isn't allowed!")) + } + + /// Decrypts a file with AES algorithm, given a path, passphrase, and ciphertext. + fn decrypt_file(&self, path: PathBuf, passphrase: &str, ciphertext: Vec) -> Result, CryptError> { + if !Path::new(&path).exists() { + log_activity!(format!("Error: {}.", CryptError::FileNotFound).as_str(), ""); + return Err(CryptError::FileNotFound); + } + + let (key_encap_mechanism, kybersize) = match KyberSize::variant() { + KyberVariant::Kyber512 => { + (KeyEncapMechanism::kyber512(), 512 as usize) + }, + KyberVariant::Kyber768 => { + (KeyEncapMechanism::kyber768(), 768 as usize) + }, + KyberVariant::Kyber1024 => { + (KeyEncapMechanism::kyber1024(), 1024 as usize) + }, + }; + let crypt_metadata = CryptographicMetadata::from( + Process::decryption(), + CryptographicMechanism::aes(), + key_encap_mechanism, + ContentType::file(), + ); + let file = FileMetadata::from(path, FileTypes::other(), FileState::encrypted()); + let infos = CryptographicInformation::from(Vec::new(), passphrase.as_bytes().to_vec(), crypt_metadata, true, Some(file)); + let mut aes = CipherAES::new(infos); + log_activity!("Creating a new cipher instance of AES.", ""); + + let data = aes.decrypt(self.kyber_data.key()?, ciphertext).unwrap(); + log_activity!("Finished:\n\t\tAlgorithm:\t\tAES,\n\t\tContent Type:\tFile\n\t\tProcess:\t\tDecryptio\n\t\tKEM:\t\t\t", format!("Kyber{}", kybersize).as_str()); + + write_log!(); + Ok(data) + } + /// Decrypts a message with AES algorithm, given the message, passphrase, and ciphertext. + fn decrypt_msg(&self, message: Vec, passphrase: &str, ciphertext: Vec) -> Result, CryptError> { + let (key_encap_mechanism, kybersize) = match KyberSize::variant() { + KyberVariant::Kyber512 => { + (KeyEncapMechanism::kyber512(), 512 as usize) + }, + KyberVariant::Kyber768 => { + (KeyEncapMechanism::kyber768(), 768 as usize) + }, + KyberVariant::Kyber1024 => { + (KeyEncapMechanism::kyber1024(), 1024 as usize) + }, + }; + let crypt_metadata = CryptographicMetadata::from( + Process::decryption(), + CryptographicMechanism::aes(), + key_encap_mechanism, + ContentType::message(), + ); + let infos = CryptographicInformation::from(message, passphrase.as_bytes().to_vec(), crypt_metadata, false, None); + let mut aes = CipherAES::new(infos); + log_activity!("Creating a new cipher instance of AES.", ""); + + let data = aes.decrypt(self.kyber_data.key()?, ciphertext).unwrap(); + log_activity!("Finished:\n\t\tAlgorithm:\t\tAES,\n\t\tContent Type:\tMessage\n\t\tProcess:\t\tDecryption\n\t\tKEM:\t\t\t", format!("Kyber{}", kybersize).as_str()); + + write_log!(); + Ok(data) + } +} + + +/// Provides Kyber encryption functions for XChaCha20 algorithm. +impl KyberFunctions for Kyber +where + KyberSize: KyberSizeVariant, +{ + /// Encrypts a file with XChaCha20 algorithm, given a path and a passphrase. + /// Returns the encrypted data and cipher. + fn encrypt_file(&mut self, path: PathBuf, passphrase: &str) -> Result<(Vec, Vec), CryptError> { + if !Path::new(&path).exists() { + log_activity!(format!("Error: {}.", CryptError::FileNotFound).as_str(), ""); + return Err(CryptError::FileNotFound); + } + + let (key_encap_mechanism, kybersize) = match KyberSize::variant() { + KyberVariant::Kyber512 => { + (KeyEncapMechanism::kyber512(), 512 as usize) + }, + KyberVariant::Kyber768 => { + (KeyEncapMechanism::kyber768(), 768 as usize) + }, + KyberVariant::Kyber1024 => { + (KeyEncapMechanism::kyber1024(), 1024 as usize) + }, + }; + let crypt_metadata = CryptographicMetadata::from( + Process::encryption(), + CryptographicMechanism::xchacha20(), + key_encap_mechanism, + ContentType::file(), + ); + let file = FileMetadata::from(path, FileTypes::other(), FileState::not_encrypted()); + let infos = CryptographicInformation::from(Vec::new(), passphrase.as_bytes().to_vec(), crypt_metadata, true, Some(file)); + let mut xchacha = CipherChaCha::new(infos, None); + log_activity!("Creating a new cipher instance of XChaCha20.", ""); + + let _ = self.kyber_data.set_nonce(hex::encode(xchacha.nonce())); + + let (data, cipher) = xchacha.encrypt(self.kyber_data.key()?).unwrap(); + log_activity!("Finished:\n\t\tAlgorithm:\t\tXChaCha20,\n\t\tContent Type:\tFile\n\t\tProcess:\t\tEncryption\n\t\tKEM:\t\t\t", format!("Kyber{}", kybersize).as_str()); + + write_log!(); + Ok((data, cipher)) + } + + /// Encrypts a message with XChaCha20 algorithm, given the message and a passphrase. + /// Returns the encrypted data and cipher. + fn encrypt_msg(&mut self, message: &str, passphrase: &str) -> Result<(Vec, Vec), CryptError> { + let (key_encap_mechanism, kybersize) = match KyberSize::variant() { + KyberVariant::Kyber512 => { + (KeyEncapMechanism::kyber512(), 512 as usize) + }, + KyberVariant::Kyber768 => { + (KeyEncapMechanism::kyber768(), 768 as usize) + }, + KyberVariant::Kyber1024 => { + (KeyEncapMechanism::kyber1024(), 1024 as usize) + }, + }; + let crypt_metadata = CryptographicMetadata::from( + Process::encryption(), + CryptographicMechanism::xchacha20(), + key_encap_mechanism, + ContentType::message(), + ); + let infos = CryptographicInformation::from(message.as_bytes().to_owned(), passphrase.as_bytes().to_vec(), crypt_metadata, false, None); + let mut xchacha = CipherChaCha::new(infos, None); + log_activity!("Creating a new cipher instance of XChaCha20.", ""); + + let _ = self.kyber_data.set_nonce(hex::encode(xchacha.nonce())); + + let (data, cipher) = xchacha.encrypt(self.kyber_data.key()?).unwrap(); + log_activity!("Finished:\n\t\tAlgorithm:\t\tXChaCha20,\n\t\tContent Type:\tMessage\n\t\tProcess:\t\tEncryption\n\t\tKEM:\t\t\t", format!("Kyber{}", kybersize).as_str()); + + write_log!(); + Ok((data, cipher)) + } + + /// Placeholder for decrypt_file, indicating operation not allowed in encryption mode. + fn decrypt_file(&self, path: PathBuf, passphrase: &str, ciphertext:Vec) -> Result, CryptError> { + Err(CryptError::new("You're currently in the process state of encryption. Decryption of files isn't allowed!")) + } + /// Placeholder for decrypt_msg, indicating operation not allowed in encryption mode. + fn decrypt_msg(&self, message: Vec, passphrase: &str, ciphertext:Vec) -> Result, CryptError> { + Err(CryptError::new("You're currently in the process state of encryption. Decryption of messanges isn't allowed!")) + } +} + + +/// Provides Kyber decryption functions for XChaCha20 algorithm. +impl KyberFunctions for Kyber +where + KyberSize: KyberSizeVariant, +{ + /// Placeholder for encrypt_file, indicating operation not allowed in decryption mode. + fn encrypt_file(&mut self, path: PathBuf, passphrase: &str) -> Result<(Vec, Vec), CryptError> { + Err(CryptError::new("You're currently in the process state of encryption. Decryption of files isn't allowed!")) + } + /// Placeholder for encrypt_msg, indicating operation not allowed in decryption mode. + fn encrypt_msg(&mut self, message: &str, passphrase: &str) -> Result<(Vec, Vec), CryptError> { + Err(CryptError::new("You're currently in the process state of encryption. Decryption of messanges isn't allowed!")) + } + + /// Decrypts a file with XChaCha20 algorithm, given a path, passphrase, and ciphertext. + /// Returns the decrypted data. + fn decrypt_file(&self, path: PathBuf, passphrase: &str, ciphertext: Vec) -> Result, CryptError> { + if !Path::new(&path).exists() { + log_activity!(format!("Error: {}.", CryptError::FileNotFound).as_str(), ""); + return Err(CryptError::FileNotFound); + } + + let (key_encap_mechanism, kybersize) = match KyberSize::variant() { + KyberVariant::Kyber512 => { + (KeyEncapMechanism::kyber512(), 512 as usize) + }, + KyberVariant::Kyber768 => { + (KeyEncapMechanism::kyber768(), 768 as usize) + }, + KyberVariant::Kyber1024 => { + (KeyEncapMechanism::kyber1024(), 1024 as usize) + }, + }; + let crypt_metadata = CryptographicMetadata::from( + Process::decryption(), + CryptographicMechanism::xchacha20(), + key_encap_mechanism, + ContentType::file(), + ); + let file = FileMetadata::from(path, FileTypes::other(), FileState::encrypted()); + let infos = CryptographicInformation::from(Vec::new(), passphrase.as_bytes().to_vec(), crypt_metadata, true, Some(file)); + let mut xchacha = CipherChaCha::new(infos, Some(self.kyber_data.nonce()?.to_string())); + log_activity!("Creating a new cipher instance of XChaCha20.", ""); + + let data = xchacha.decrypt(self.kyber_data.key()?, ciphertext).unwrap(); + log_activity!("Finished:\n\t\tAlgorithm:\t\tXChaCha20,\n\t\tContent Type:\tFile\n\t\tProcess:\t\tDecryption\n\t\tKEM:\t\t\t", format!("Kyber{}", kybersize).as_str()); + + write_log!(); + Ok(data) + } + /// Decrypts a message with XChaCha20 algorithm, given the message, passphrase, and ciphertext. + /// Returns the decrypted data. + fn decrypt_msg(&self, message: Vec, passphrase: &str, ciphertext: Vec) -> Result, CryptError> { + let (key_encap_mechanism, kybersize) = match KyberSize::variant() { + KyberVariant::Kyber512 => { + (KeyEncapMechanism::kyber512(), 512 as usize) + }, + KyberVariant::Kyber768 => { + (KeyEncapMechanism::kyber768(), 768 as usize) + }, + KyberVariant::Kyber1024 => { + (KeyEncapMechanism::kyber1024(), 1024 as usize) + }, + }; + let crypt_metadata = CryptographicMetadata::from( + Process::decryption(), + CryptographicMechanism::xchacha20(), + key_encap_mechanism, + ContentType::message(), + ); + let infos = CryptographicInformation::from(message, passphrase.as_bytes().to_vec(), crypt_metadata, false, None); + let mut xchacha = CipherChaCha::new(infos, Some(self.kyber_data.nonce()?.to_string())); + log_activity!("Creating a new cipher instance of XChaCha20.", ""); + + let data = xchacha.decrypt(self.kyber_data.key()?, ciphertext).unwrap(); + log_activity!("Finished:\n\t\tAlgorithm:\t\tXChaCha20,\n\t\tContent Type:\tMessage\n\t\tProcess:\t\tDecryption\n\t\tKEM:\t\t\t", format!("Kyber{}", kybersize).as_str()); + + println!("data: {:?}", data); + write_log!(); + Ok(data) + } +} diff --git a/src/Core/kyber/mod.rs b/src/Core/kyber/mod.rs new file mode 100644 index 0000000..f10acaf --- /dev/null +++ b/src/Core/kyber/mod.rs @@ -0,0 +1,266 @@ +pub mod KeyKyber; +mod kyber_crypto; +pub use kyber_crypto::*; +use pqcrypto_traits::kem::{PublicKey, SecretKey, SharedSecret, Ciphertext}; +use crate::{ + *, + log_activity, + cryptography::*, + error::CryptError, + hmac_sign::*, + FileTypes, + FileState, + FileMetadata, + KeyTypes, + Key, + Core::CryptographicFunctions, +}; +use std::{ + path::{PathBuf, Path}, + collections::HashMap, + marker::PhantomData, + result::Result, + io::{Read, Write}, + fs, +}; + +/// Trait for Kyber cryptographic functions. +pub trait KyberFunctions { + /// Encrypts a file at a given path with a passphrase, returning the encrypted data and nonce. + fn encrypt_file(&mut self, path: PathBuf, passphrase: &str) -> Result<(Vec, Vec), CryptError>; + /// Encrypts a message with a passphrase, returning the encrypted data and nonce. + fn encrypt_msg(&mut self, message: &str, passphrase: &str) -> Result<(Vec, Vec), CryptError>; + + /// Decrypts a file at a given path with a passphrase and ciphertext, returning the decrypted data. + fn decrypt_file(&self, path: PathBuf, passphrase: &str, ciphertext: Vec) -> Result, CryptError>; + /// Decrypts a message with a passphrase and ciphertext, returning the decrypted data. + fn decrypt_msg(&self, message: Vec, passphrase: &str, ciphertext: Vec) -> Result, CryptError>; +} + + +/// Enum representing Kyber variants. +pub enum KyberVariant { + Kyber512, + Kyber768, + Kyber1024, +} + +/// Trait to specify Kyber size variants. +pub trait KyberSizeVariant { + /// Returns the Kyber variant. + fn variant() -> KyberVariant; +} + +impl KyberSizeVariant for Kyber512 { + fn variant() -> KyberVariant { KyberVariant::Kyber512 } +} + +impl KyberSizeVariant for Kyber768 { + fn variant() -> KyberVariant { KyberVariant::Kyber768 } +} + +impl KyberSizeVariant for Kyber1024 { + fn variant() -> KyberVariant { KyberVariant::Kyber1024 } +} + +pub struct Kyber512; +pub struct Kyber768; +pub struct Kyber1024; + +pub struct AES; +pub struct XChaCha20; + +pub struct Encryption; +pub struct Decryption; + +pub struct File; +pub struct Message; + + +/// Represents the data structure for Kyber algorithm, including key and nonce. +#[derive(PartialEq, Debug, Clone)] +pub struct KyberData { + key: Vec, + nonce: String, +} + +impl KyberData { + /// Returns the cryptographic key. + pub fn key(&self) -> Result, CryptError> { + let key = &self.key; + let key = key.to_vec(); + Ok(key) + } + /// Returns the nonce. + pub fn nonce(&self) -> Result<&str, CryptError> { + let nonce = &self.nonce; + Ok(nonce) + } + /// Sets the nonce. + pub fn set_nonce(&mut self, nonce: String) -> Result<(), CryptError> { + self.nonce = nonce; + Ok(()) + } + /// Sets the cryptographic key. + pub fn set_key(&mut self, key: Vec) -> Result<(), CryptError> { + self.key = key; + Ok(()) + } +} + +/// Represents a generic Kyber structure with templated parameters for process status, Kyber size, content status, and algorithm parameter. +pub struct Kyber +where + KyberSize: KyberSizeVariant, +{ + kyber_data: KyberData, + hmac_size: usize, + content_state: PhantomData, + kyber_state: PhantomData, + algorithm_state: PhantomData, + process_state: PhantomData, +} + +impl Kyber { + /// Constructs a new Kyber instance with a key and an optional nonce. + pub fn new(key: Vec, nonce: Option) -> Result { + let nonce = nonce.map_or(String::new(), |data| data); + Ok(Self { + kyber_data: KyberData { key, nonce }, + hmac_size: 512, + content_state: PhantomData, + kyber_state: PhantomData, + algorithm_state: PhantomData, + process_state: PhantomData, + }) + } + + /// Returns the cryptographic key. + pub fn get_key(&self) -> Result, CryptError> { + self.kyber_data.key() + } + + /// Returns the nonce. + pub fn get_nonce(&self) -> Result<&str, CryptError> { + self.kyber_data.nonce() + } + + pub fn hmac_sha256(&mut self) -> Result<(), CryptError> { + self.hmac_size = 256; + Ok(()) + } +} + +/// Usable when KyberSize = Kyber1024 +impl Kyber { + pub fn kyber768(self) -> Result, CryptError> { + Ok(Kyber:: {kyber_data: self.kyber_data, hmac_size: self.hmac_size, process_state: self.process_state, kyber_state: PhantomData::, content_state: self.content_state, algorithm_state: self.algorithm_state}) + } + pub fn kyber512(self) -> Result, CryptError> { + Ok(Kyber:: {kyber_data: self.kyber_data, hmac_size: self.hmac_size, process_state: self.process_state, kyber_state: PhantomData::, content_state: self.content_state, algorithm_state: self.algorithm_state}) + } +} + +/// Usable when KyberSize = Kyber768 +impl Kyber { + pub fn kyber1024(self) -> Result, CryptError> { + Ok(Kyber:: {kyber_data: self.kyber_data, hmac_size: self.hmac_size, process_state: self.process_state, kyber_state: PhantomData::, content_state: self.content_state, algorithm_state: self.algorithm_state}) + } + pub fn kyber512(self) -> Result, CryptError> { + Ok(Kyber:: {kyber_data: self.kyber_data, hmac_size: self.hmac_size, process_state: self.process_state, kyber_state: PhantomData::, content_state: self.content_state, algorithm_state: self.algorithm_state}) + } +} + +/// Usable when KyberSize = Kyber512 +impl Kyber { + pub fn kyber1024(self) -> Result, CryptError> { + Ok(Kyber:: {kyber_data: self.kyber_data, hmac_size: self.hmac_size, process_state: self.process_state, kyber_state: PhantomData::, content_state: self.content_state, algorithm_state: self.algorithm_state}) + } + pub fn kyber768(self) -> Result, CryptError> { + Ok(Kyber:: {kyber_data: self.kyber_data, hmac_size: self.hmac_size, process_state: self.process_state, kyber_state: PhantomData::, content_state: self.content_state, algorithm_state: self.algorithm_state}) + } +} + +/// Usable when AlgorithmParam = AES +impl Kyber { + pub fn xchacha20(self) -> Kyber { + Kyber { + kyber_data: self.kyber_data, + hmac_size: self.hmac_size, + content_state: PhantomData, + kyber_state: PhantomData, + algorithm_state: PhantomData, + process_state: PhantomData, + } + } +} + +/// Usable when AlgorithmParam = XChaCha20 +impl Kyber { + pub fn aes(self) -> Kyber { + Kyber { + kyber_data: self.kyber_data, + hmac_size: self.hmac_size, + content_state: PhantomData, + kyber_state: PhantomData, + algorithm_state: PhantomData, + process_state: PhantomData, + } + } +} +/// Usable when ContentStatus = File +impl Kyber { + pub fn message(self) -> Kyber { + Kyber { + kyber_data: self.kyber_data, + hmac_size: self.hmac_size, + content_state: PhantomData, + kyber_state: PhantomData, + algorithm_state: PhantomData, + process_state: PhantomData, + } + } +} + +/// Usable when ContentStatus = Message +impl Kyber { + pub fn file(self) -> Kyber { + Kyber { + kyber_data: self.kyber_data, + hmac_size: self.hmac_size, + content_state: PhantomData, + kyber_state: PhantomData, + algorithm_state: PhantomData, + process_state: PhantomData, + } + } +} + +/// Usable when ProcessStatus = Encryption +impl Kyber { + pub fn decryption(self) -> Kyber { + Kyber { + kyber_data: self.kyber_data, + hmac_size: self.hmac_size, + content_state: PhantomData, + kyber_state: PhantomData, + algorithm_state: PhantomData, + process_state: PhantomData, + } + } +} + +/// Usable when ProcessStatus = Decryption +impl Kyber { + pub fn encryption(self) -> Kyber { + Kyber { + kyber_data: self.kyber_data, + hmac_size: self.hmac_size, + content_state: PhantomData, + kyber_state: PhantomData, + algorithm_state: PhantomData, + process_state: PhantomData, + } + } +} + diff --git a/src/Core/mod.rs b/src/Core/mod.rs new file mode 100644 index 0000000..4c482c3 --- /dev/null +++ b/src/Core/mod.rs @@ -0,0 +1,64 @@ +use crate::{cryptography::*, error::CryptError, hmac_sign::*}; +pub mod KDF; +pub mod kyber; +pub use kyber::KeyKyber::*; + +/// The `cipher_aes` module implements the AES (Advanced Encryption Standard) algorithm for secure data encryption and decryption, providing a robust symmetric key cryptography solution. +pub mod cipher_aes; +/// The `cipher_xchacha` module offers encryption and decryption functionalities using the XChaCha20 algorithm, extending ChaCha for higher nonce sizes and additional security. +pub mod cipher_xchacha; + +pub enum KeyControlVariant { + Kyber1024(KeyControl), + Kyber768(KeyControl), + Kyber512(KeyControl), +} + +impl KeyControlVariant { + // Encapsulates the logic to create different KeyControl variants + pub fn new(keytype: KeyEncapMechanism) -> Self { + match keytype { + KeyEncapMechanism::Kyber1024 => Self::Kyber1024(KeyControl::::new()), + KeyEncapMechanism::Kyber768 => Self::Kyber768(KeyControl::::new()), + KeyEncapMechanism::Kyber512 => Self::Kyber512(KeyControl::::new()), + } + } + pub fn encap(&self, public_key: &[u8]) -> Result<(Vec, Vec), CryptError> { + match self { + KeyControlVariant::Kyber1024(k) => k.encap(public_key), + KeyControlVariant::Kyber768(k) => k.encap(public_key), + KeyControlVariant::Kyber512(k) => k.encap(public_key), + } + } + + pub fn decap(&self, secret_key: &[u8], ciphertext: &[u8]) -> Result, CryptError> { + match self { + KeyControlVariant::Kyber1024(k) => k.decap(secret_key, ciphertext), + KeyControlVariant::Kyber768(k) => k.decap(secret_key, ciphertext), + KeyControlVariant::Kyber512(k) => k.decap(secret_key, ciphertext), + } + } +} + +/// Defines the functionalities for cryptographic operations, providing abstract methods for +/// encryption and decryption that need to be implemented by specific cryptographic algorithms. +pub trait CryptographicFunctions { + /// Encrypts data using a public key, returning the encrypted data and potentially a new key. + /// + /// # Parameters + /// - `public_key`: The public key used for encryption. + /// + /// # Returns + /// A result containing the encrypted data and a new key on success, or a `CryptError` on failure. + fn encrypt(&mut self, public_key: Vec) -> Result<(Vec, Vec), CryptError>; + + /// Decrypts data using a secret key and a given ciphertext. + /// + /// # Parameters + /// - `secret_key`: The secret key used for decryption. + /// - `ciphertext`: The ciphertext to be decrypted. + /// + /// # Returns + /// A result containing the decrypted data on success, or a `CryptError` on failure. + fn decrypt(&mut self, secret_key: Vec, ciphertext: Vec) -> Result, CryptError>; +} diff --git a/src/KeyControl/file.rs b/src/KeyControl/file.rs new file mode 100644 index 0000000..1847b8e --- /dev/null +++ b/src/KeyControl/file.rs @@ -0,0 +1,166 @@ +use std::{ + path::{Path, PathBuf}, + io::{Seek, Write}, + fs::{self, File}, +}; +use crate::error::CryptError; + +use crate::KeyControl::*; + + +/// Manages metadata related to a file, including its location, type, and state within a cryptographic context. +#[derive(PartialEq, Debug, Clone)] +pub struct FileMetadata { + /// The filesystem path where the file is located. + location: PathBuf, + /// The type of the file, as defined in `FileTypes`. + file_type: FileTypes, + /// The current state of the file, as defined in `FileState`. + file_state: FileState, +} + +/// Manages metadata and operations for cryptographic files, including key files, messages, and ciphertexts. +/// +/// Provides functionality for loading, saving, and manipulating file paths and contents according to the cryptographic context. +impl FileMetadata { + /// Creates a new `FileMetadata` instance with default values. + /// + /// # Returns + /// A new instance of `FileMetadata` with empty location, and default types set to `Other`. + pub fn new() -> Self { + FileMetadata { + location: PathBuf::new(), + file_type: FileTypes::Other, + file_state: FileState::Other, + } + } + + /// Constructs a `FileMetadata` instance from specified parameters. + /// + /// # Parameters + /// - `location`: The filesystem path where the file is located. + /// - `file_type`: The type of file, determining how it is processed and labeled. + /// - `file_state`: The state of the file, influencing how it should be treated in cryptographic operations. + /// + /// # Returns + /// A new instance of `FileMetadata` configured with the provided details. + pub fn from(location: PathBuf, file_type: FileTypes, file_state: FileState) -> Self { + FileMetadata { + location, + file_type, + file_state, + } + } + + // Setters + /// Sets the file location. + pub fn set_location(&mut self, location: PathBuf) { + self.location = location; + } + + /// Sets the file type. + pub fn set_file_type(&mut self, file_type: FileTypes) { + self.file_type = file_type; + } + + /// Sets the file state. + pub fn set_file_state(&mut self, file_state: FileState) { + self.file_state = file_state; + } + + // Getters + /// Gets the file type. + pub fn file_type(&self) -> &FileTypes { + &self.file_type + } + + /// Gets the file state. + pub fn file_state(&self) -> &FileState { + &self.file_state + } + + /// Retrieves the file's location as a `PathBuf`. + /// + /// # Returns + /// The path to the file encapsulated within this `FileMetadata` instance. + pub fn location(&self) -> Result { + let dir_str = &self.location.as_os_str().to_str().unwrap(); + let dir = PathBuf::from(dir_str); + Ok(dir) + } + + /// Generates start and end tags based on the file's type, used for wrapping content in specific file formats. + /// + /// # Returns + /// A tuple containing start and end tags as strings, or a `CryptError` if the operation fails. + pub fn tags(&self) -> Result<(String, String), CryptError> { + let (start_label, end_label) = match self.file_type { + FileTypes::PublicKey => ("-----BEGIN PUBLIC KEY-----\n", "\n-----END PUBLIC KEY-----"), + FileTypes::SecretKey => ("-----BEGIN SECRET KEY-----\n", "\n-----END SECRET KEY-----"), + FileTypes::Message => ("-----BEGIN MESSAGE-----\n", "\n-----END MESSAGE-----"), + FileTypes::Ciphertext => ("-----BEGIN CIPHERTEXT-----\n", "\n-----END CIPHERTEXT-----"), + FileTypes::File => unreachable!(), + FileTypes::Other => unreachable!(), + }; + Ok((start_label.to_string(), end_label.to_string())) + } + + /// Loads the file's content, decoding it if necessary and stripping any encapsulation tags. + /// + /// # Returns + /// The raw content of the file as a byte vector, or a `CryptError` if loading or processing fails. + pub fn load(&self) -> Result, CryptError> { + let file_content = fs::read_to_string(&self.location).map_err(|e| CryptError::from(e))?; + let (start_label, end_label) = self.tags()?; + + let start = file_content.find(&start_label) + .ok_or(CryptError::InvalidMessageFormat)? + start_label.len(); + let end = file_content.rfind(&end_label) + .ok_or(CryptError::InvalidMessageFormat)?; + + let content = &file_content[start..end].trim(); + hex::decode(content).map_err(|_| CryptError::HexDecodingError("Invalid hex format".into())) + } + + /// Retrieves the parent directory of the file's location. + /// + /// # Returns + /// The path to the parent directory as a `PathBuf`, or an empty path if the location is root or unset. + pub fn parent(&self) -> Result { + let parent = self.location.parent(); + let parent = match parent { + Some(parent) => PathBuf::from(parent), + _ => {PathBuf::new()} + }; + Ok(parent) + } + + /// Saves content to the file's location, wrapping it with appropriate start and end tags. + /// + /// # Parameters + /// - `content`: The raw content to save to the file. + /// + /// # Returns + /// An `Ok(())` upon successful save or a `CryptError` if the operation fails. + pub fn save(&self, content: &[u8]) -> Result<(), CryptError> { + if let Some(parent_dir) = self.location.parent() { + if !parent_dir.is_dir() { + std::fs::create_dir_all(parent_dir).map_err(|_| CryptError::WriteError)?; + } + } + + let (start_label, end_label) = self.tags()?; + let content = format!("{}{}{}", start_label, hex::encode(content), end_label); + let mut buffer = File::create(&self.location).map_err(|_| CryptError::WriteError)?; + let _ = buffer.write(content.as_bytes()); + Ok(()) + } + + /// Reads the raw content of the file without processing. + /// + /// # Returns + /// The raw content of the file as a byte vector, or a `CryptError` if the read operation fails. + pub fn read(&self) -> Result, CryptError> { + Ok(fs::read(&self.location).map_err(|e| CryptError::from(e))?) + } +} \ No newline at end of file diff --git a/src/KeyControl/key.rs b/src/KeyControl/key.rs new file mode 100644 index 0000000..025f4e1 --- /dev/null +++ b/src/KeyControl/key.rs @@ -0,0 +1,177 @@ +use crate::error::CryptError; +use pqcrypto_kyber::kyber1024; +use pqcrypto_kyber::kyber1024::*; +use pqcrypto_traits::kem::{PublicKey, SecretKey, SharedSecret, Ciphertext}; +use crate::KeyControl::*; +use std::{ + path::{Path, PathBuf}, +}; + +/// Represents a cryptographic key, including its type and raw content. +#[derive(PartialEq, Debug, Clone)] +pub struct Key { + /// The type of the key, as defined in `KeyTypes`. + key_type: KeyTypes, + /// The raw content of the key. + content: Vec +} + +/// Represents a cryptographic key with its type and content. +/// It provides functionalities to manipulate and store keys in various formats. +impl Key { + /// Constructs a new `Key` with specified type and content, optimizing storage based on the key type. + /// + /// # Parameters + /// - `key_type`: The type of the key (public, secret, ciphertext, shared secret). + /// - `content`: The raw content of the key. + /// + /// # Returns + /// A new instance of `Key`. + pub fn new(key_type: KeyTypes, content: Vec) -> Self { + let content = Self::optimize(&key_type, content); + Key { + key_type, + content, + } + } + + /// Optimizes the storage of the key based on its type. + /// + /// # Parameters + /// - `key_type`: The type of the key being optimized. + /// - `content`: The raw key content. + /// + /// # Returns + /// Optimized key content as a byte vector. + fn optimize(key_type: &KeyTypes, content: Vec) -> Vec { + let key: Vec = match key_type { + KeyTypes::PublicKey => { + let key: kyber1024::PublicKey = PublicKey::from_bytes(&content).unwrap(); + key.as_bytes().to_vec() + }, + KeyTypes::SecretKey => { + let key: kyber1024::SecretKey = SecretKey::from_bytes(&content).unwrap(); + key.as_bytes().to_vec() + }, + KeyTypes::Ciphertext => { + let key: kyber1024::Ciphertext = Ciphertext::from_bytes(&content).unwrap(); + key.as_bytes().to_vec() + }, + KeyTypes::SharedSecret => { + let key: kyber1024::SharedSecret = SharedSecret::from_bytes(&content).unwrap(); + key.as_bytes().to_vec() + }, + _ => { + content + } + }; + key + } + + + /// Factory methods for creating specific types of keys by building new Self elements. + pub fn new_public_key(key: Vec) -> Self { + Key { + key_type: KeyTypes::PublicKey, + content: key, + } + } + pub fn new_secret_key(key: Vec) -> Self { + Key { + key_type: KeyTypes::SecretKey, + content: key, + } + } + pub fn new_ciphertext(key: Vec) -> Self { + Key { + key_type: KeyTypes::Ciphertext, + content: key, + } + } + pub fn new_shared_secret(key: Vec) -> Self { + Key { + key_type: KeyTypes::SharedSecret, + content: key, + } + } + + /// Accessors for the key's properties. + pub fn get(&self) -> Result<&Key, CryptError> { + Ok(&self) + } + pub fn key_type(&self) -> Result<&KeyTypes, CryptError> { + Ok(&self.key_type) + } + pub fn content(&self) -> Result<&[u8], CryptError> { + Ok(&self.content) + } + + /// Safely stores the key to a specified path. + /// + /// # Parameters + /// - `base_path`: The base directory path where the key will be saved. + /// + /// # Returns + /// An `Ok(())` on success or a `CryptError` on failure. + pub fn save(&self, base_path: PathBuf) -> Result<(), CryptError> { + let file_name = match self.key_type { + KeyTypes::PublicKey => "public_key.pub", + KeyTypes::SecretKey => "secret_key.sec", + KeyTypes::Ciphertext => "ciphertext.ct", + KeyTypes::SharedSecret => return Err(CryptError::UnsupportedOperation), + _ => return Err(CryptError::InvalidKeyType), + }; + + let path = base_path.join(file_name); + let file_metadata = FileMetadata::from(path, self.file_type_from_key_type(), FileState::Encrypted); + + file_metadata.save(&self.content) + } + + fn file_type_from_key_type(&self) -> FileTypes { + match self.key_type { + KeyTypes::PublicKey => FileTypes::PublicKey, + KeyTypes::SecretKey => FileTypes::SecretKey, + KeyTypes::Ciphertext => FileTypes::Ciphertext, + _ => FileTypes::Other, + } + } + + /// Encapsulates the key, generating a ciphertext and shared secret. + /// + /// # Returns + /// A tuple containing the ciphertext and shared secret as `Key` instances, or a `CryptError`. + pub fn encap(&self) -> Result<(Key,Key), CryptError> { + match self.key_type { + KeyTypes::PublicKey => { + let pk = PublicKey::from_bytes(self.content()?).unwrap(); + let (ss, ct) = encapsulate(&pk); + let ciphertext = Key::new_ciphertext(ct.as_bytes().to_vec()); + let shared_secret = Key::new_shared_secret(ss.as_bytes().to_vec()); + //Ok((ct.as_bytes().to_vec(), ss.as_bytes().to_vec())); + Ok((ciphertext, shared_secret)) + } + _ => Err(CryptError::EncapsulationError) + } + } + + /// Decapsulates the ciphertext using the secret key, retrieving the shared secret. + /// + /// # Parameters + /// - `ciphertext`: The ciphertext `Key` to be decapsulated. + /// + /// # Returns + /// The shared secret as a `Key`, or a `CryptError`. + pub fn decap(&self, ciphertext: Key) -> Result { + match self.key_type { + KeyTypes::SecretKey => { + let ct = Ciphertext::from_bytes(ciphertext.content()?).unwrap(); + let sk = SecretKey::from_bytes(self.content()?).unwrap(); + let ss2 = decapsulate(&ct, &sk); + let shared_secret = Key::new_shared_secret(ss2.as_bytes().to_vec()); + Ok(shared_secret) + } + _ => Err(CryptError::DecapsulationError) + } + } +} \ No newline at end of file diff --git a/src/KeyControl/mod.rs b/src/KeyControl/mod.rs new file mode 100644 index 0000000..4b97a4b --- /dev/null +++ b/src/KeyControl/mod.rs @@ -0,0 +1,134 @@ +use crate::error::CryptError; +use pqcrypto_kyber::kyber1024; +use pqcrypto_kyber::kyber1024::*; +use pqcrypto_traits::kem::{PublicKey, SecretKey, SharedSecret, Ciphertext}; + +// A module defining the cryptographic keypair functionality. +//mod keypair; +/// A module defining the cryptographic key functionality. +mod key; +/// A module for handling file-related metadata and operations in a cryptographic context. +pub mod file; + +pub use key::Key; +pub use file::*; +//pub use keypair::*; + +use std::path::PathBuf; + +/// Enumerates the types of cryptographic keys supported by the system. +#[derive(PartialEq, Debug, Copy, Clone)] +pub enum KeyTypes { + /// Represents an unspecified or undefined key type. + None, + /// Represents a public key. + PublicKey, + /// Represents a secret (private) key. + SecretKey, + /// Represents a ciphertext, typically the result of encrypting some plaintext. + Ciphertext, + /// Represents a shared secret, typically derived through key exchange mechanisms. + SharedSecret, +} + +impl KeyTypes { + pub fn none() -> Self { + Self::None + } + pub fn public_key() -> Self { + Self::PublicKey + } + pub fn secret_key() -> Self { + Self::SecretKey + } + pub fn Ciphertext() -> Self { + Self::Ciphertext + } + pub fn shared_secret() -> Self { + Self::SharedSecret + } + +} + + +/// Enumerates the types of files recognized by the cryptographic system. +#[derive(PartialEq, Debug, Copy, Clone)] +pub enum FileTypes { + /// Represents an unspecified or other type of file not explicitly listed. + Other, + /// Represents a file containing a public key. + PublicKey, + /// Represents a file containing a secret (private) key. + SecretKey, + /// Represents a file containing ciphertext. + Ciphertext, + /// Represents a file containing a plaintext message. + Message, + /// Represents a generic file, without specifying its content type. + File, +} + +impl FileTypes { + /// Represents an unspecified or other type of file not explicitly listed. + pub fn other() -> Self { + Self::Other + } + /// Represents a file containing a public key. + pub fn public_key() -> Self { + Self::PublicKey + } + /// Represents a file containing a secret (private) key. + pub fn Secret_key() -> Self { + Self::SecretKey + } + /// Represents a file containing ciphertext. + pub fn ciphertext() -> Self { + Self::Ciphertext + } + /// Represents a file containing a plaintext message. + pub fn message() -> Self { + Self::Message + } + /// Represents a generic file, without specifying its content type. + pub fn file() -> Self { + Self::File + } +} + +/// Enumerates possible states a file can be in, especially in the context of encryption and decryption. +#[derive(PartialEq, Debug, Copy, Clone)] +pub enum FileState { + /// Represents an unspecified or other state not explicitly listed. + Other, + /// Represents a file that has not yet been encrypted. + NotEncrypted, + /// Represents a file that has been encrypted. + Encrypted, + /// Represents a file that has been decrypted. + Decrypted, + /// Indicates the file content is stored in hexadecimal format. + Hex, +} + +impl FileState { + /// Represents an unspecified or other state not explicitly listed. + pub fn other() -> Self { + Self::Other + } + /// Represents a file that has not yet been encrypted. + pub fn not_encrypted() -> Self { + Self::NotEncrypted + } + /// Represents a file that has been encrypted. + pub fn encrypted() -> Self { + Self::Encrypted + } + /// Represents a file that has been decrypted. + pub fn decrypted() -> Self { + Self::Decrypted + } + /// Indicates the file content is stored in hexadecimal format. + pub fn hex() -> Self { + Self::Hex + } +} \ No newline at end of file diff --git a/src/cryptography/cryptographic.rs b/src/cryptography/cryptographic.rs new file mode 100644 index 0000000..d7bb5ae --- /dev/null +++ b/src/cryptography/cryptographic.rs @@ -0,0 +1,236 @@ +use crate::{ + KeyControl::*, + cryptography::{ + CipherAES, + *, + }, +}; +use std::{ + fs::File, + io::Write, +}; + +/// Enum defining cryptographic mechanisms supported by the system. +impl CryptographicMechanism { + /// Creates a new instance defaulting to AES. + pub fn new() -> Self { + Self::AES + } + /// Specifies AES as the cryptographic mechanism. + pub fn aes() -> Self { + Self::AES + } + /// Specifies XChaCha20 as the cryptographic mechanism. + pub fn xchacha20() -> Self { + Self::XChaCha20 + } +} + +/// Enum defining the process type (encryption or decryption). +impl Process { + /// Specifies the process as encryption. + pub fn encryption() -> Self { + Self::Encryption + } + /// Specifies the process as decryption. + pub fn decryption() -> Self { + Self::Decryption + } +} + +/// Enum defining key encapsulation mechanisms supported. +impl KeyEncapMechanism { + /// Creates a new instance defaulting to Kyber1024. + pub fn new() -> Self { + Self::Kyber1024 + } + /// Specifies Kyber1024 as the key encapsulation mechanism. + pub fn kyber1024() -> Self { + Self::Kyber1024 + } + /// Specifies Kyber768 as the key encapsulation mechanism. + pub fn kyber768() -> Self { + Self::Kyber768 + } + /// Specifies Kyber512 as the key encapsulation mechanism. + pub fn kyber512() -> Self { + Self::Kyber512 + } +} + +/// Enum defining the type of content being encrypted or decrypted. +impl ContentType { + /// Creates a new instance defaulting to file. + pub fn new() -> Self { + Self::File + } + /// Specifies the content as a file. + pub fn file() -> Self { + Self::File + } + /// Specifies the content as a message. + pub fn message() -> Self { + Self::Message + } +} + +/// Stores cryptographic settings for an operation. +impl CryptographicMetadata { + /// Constructs a new instance with default values. + pub fn new() -> Self { + CryptographicMetadata { + process: Process::encryption(), + encryption_type: CryptographicMechanism::new(), + key_type: KeyEncapMechanism::new(), + content_type: ContentType::new(), + } + } + + /// Constructs a new instance with specified values. + pub fn from( + process: Process, + encryption_type: CryptographicMechanism, + key_type: KeyEncapMechanism, + content_type: ContentType, + ) -> Self { + CryptographicMetadata { + process, + encryption_type, + key_type, + content_type, + } + } + + /// Accessor method for process property + pub fn process(&self) -> Result { + Ok(self.process) + } + + /// Accessor method for encryption_type property + pub fn encryption_type(self) -> Result { + Ok(self.encryption_type) + } + + /// Accessor method for key_type property + pub fn key_type(self) -> Result { + Ok(self.key_type) + } + + /// Accessor method for content_type property + pub fn content_type(self) -> Result { + Ok(self.content_type) + } +} + +/// Holds all cryptographic information for an encryption/decryption operation. +impl CryptographicInformation { + /// Constructs a new instance with empty values and default metadata. + pub fn new() -> Self { + CryptographicInformation { + content: Vec::new(), + passphrase: Vec::new(), + metadata: CryptographicMetadata::new(), + safe: false, + location: None + } + } + + /// Checks if the cryptographic information contains a file. + pub fn contains_file(&self) -> Result { + let contains_file = match &self.location { + Some(_) => true, + None => false + }; + Ok(contains_file) + } + + /// Sets the content to be encrypted or decrypted. + pub fn set_data(&mut self, data: &[u8]) -> Result<(), CryptError> { + let mut data = data.to_vec(); + self.content = data; + Ok(()) + } + + /// Prepares a file name for saving, considering its extension. + fn prepare_file_name_for_saving(&self, file_path: &PathBuf) -> Result { + let mut new_file_path = file_path.clone(); + + // Check if the file extension is .enc + if let Some(extension) = file_path.extension().and_then(|ext| ext.to_str()) { + if extension == "enc" { + // If the extension is .enc, remove it to get the original file name + new_file_path.set_extension(""); + } else { + // If the file does not have an .enc extension, append .enc to the file name + let file_name_with_enc = format!("{}.enc", file_path.to_string_lossy()); + new_file_path = file_path.with_file_name(file_name_with_enc); + } + } else { + // If the file has no extension, simply append .enc + let file_name_with_enc = format!("{}.enc", file_path.to_string_lossy()); + new_file_path = file_path.with_file_name(file_name_with_enc); + } + + Ok(new_file_path) + } + + /// Safely saves the content to a file at the specified location. + pub fn safe_file(&mut self) -> Result<(), CryptError> { + let file_path = self.location().map_err(|_| CryptError::PathError)?; + + // Use the new function to prepare the file name + let file_path_with_enc = self.prepare_file_name_for_saving(&file_path)?; + + if let Some(parent_dir) = file_path_with_enc.parent() { + if !parent_dir.is_dir() { + std::fs::create_dir_all(parent_dir).map_err(|_| CryptError::WriteError)?; + } + } + + let mut buffer = File::create(&file_path_with_enc).map_err(|_| CryptError::WriteError)?; + buffer.write_all(&self.content).map_err(|_| CryptError::WriteError)?; + + Ok(()) + } + + /// Indicates whether the cryptographic operation is considered safe. + pub fn safe(&self) -> Result { + Ok(self.safe) + } + + /// Returns the file location. + pub fn location(&self) -> Result { + let file = match &self.location { + Some(path) => Ok(path.location()?), + _ => Err(CryptError::PathError) + }; + file + } + + /// Constructs a new instance with specified values. + pub fn from( + content: Vec, + passphrase: Vec, + metadata: CryptographicMetadata, + safe: bool, + location: Option + ) -> Self { + CryptographicInformation { + content, + passphrase, + metadata, + safe, + location + } + } + + // Accessor method for content. + pub fn content(&self) -> Result<&[u8], CryptError> { + Ok(&self.content) + } + + // Accessor method for passphrase + pub fn passphrase(&self) -> Result<&[u8], CryptError> { + Ok(&self.passphrase) + } +} \ No newline at end of file diff --git a/src/cryptography/hmac_sign/mod.rs b/src/cryptography/hmac_sign/mod.rs new file mode 100644 index 0000000..497c03d --- /dev/null +++ b/src/cryptography/hmac_sign/mod.rs @@ -0,0 +1,195 @@ +mod sign; +pub use sign::*; +use hmac::{Hmac, Mac}; +use sha2::{Sha512, Sha256}; +use crate::{cryptography::*, error::*}; +use crate::error::SigningErr; + +/// Defines the operation being performed, either verification or signing. +#[derive(PartialEq, Debug, Copy, Clone)] +pub enum Operation { + Verify, + Sign, +} + +/// Defines the types of signatures supported by the system. +#[derive(PartialEq, Debug, Copy, Clone)] +pub enum SignType { + Sha512, + Sha256, + Falcon, + Dilithium +} + +/// Represents a signing operation including the data and metadata for the operation. +#[derive(PartialEq, Debug, Clone)] +pub struct Sign { + pub data: SignatureData, + pub status: Operation, + pub hash_type: SignType, + pub length: usize, + pub veryfied: bool +} + +/// Contains the data to be signed or verified, alongside necessary metadata like passphrase. +#[derive(PartialEq, Debug, Clone)] +pub struct SignatureData { + pub data: Vec, + pub passphrase: Vec, + pub hmac: Vec, + pub concat_data: Vec, +} + +/// Defines the type of data associated with a signature. +#[derive(PartialEq, Debug, Copy, Clone)] +pub enum SignatureDataType { + None, + SignedMessage, + DetachedSignature, + PublicKey, + SecretKey, +} + +/// Defines whether a signature is attached to the message or detached. +#[derive(PartialEq, Debug, Copy, Clone)] +pub enum SignatureType { + UnSigned, + SignedMessage, + DetachedSignature, +} + +/// Represents a key used in the signature process, identifying its type and content. +#[derive(PartialEq, Debug, Clone)] +pub struct SignatureKey { + pub data: Vec, + pub key_type: SignatureDataType, +} + +/// Represents the mechanism used for signing, along with the signature and public key used. +#[derive(PartialEq, Debug, Clone)] +pub struct SignatureMechanism { + pub signature: Vec, + pub public_key: SignatureKey, + pub signature_type: SignatureType, +} + +impl SignatureMechanism { + /// Constructs a new `SignatureMechanism` with a public key. + pub fn new(public_key: Vec) -> Self { + let mut public = SignatureKey::new(); + let _ = public.set_public_key(public_key).unwrap(); + let signature_type = SignatureType::UnSigned; + SignatureMechanism { signature: Vec::new(), public_key: public, signature_type } + } + + /// Sets the signature for the mechanism. but doesn't define the type of signature. + pub fn set_signature(&mut self, signature: Vec) -> Result<&[u8], SigningErr> { + self.signature = signature; + Ok(&self.signature) + } + + /// Retrieves the signature. + pub fn signature(&self) -> Result<&[u8], SigningErr> { + Ok(&self.signature) + } + + /// Defines the signed message signature. + pub fn set_signed_msg(&mut self, signature: Vec) -> Result<(), SigningErr> { + self.signature = signature; + self.signature_type = SignatureType::SignedMessage; + Ok(()) + } + + /// Defines the detached signature. + pub fn set_detached_sign(&mut self, signature: Vec) -> Result<(), SigningErr> { + self.signature = signature; + self.signature_type = SignatureType::DetachedSignature; + Ok(()) + } + + /// Checks if the message is a signed message (true) or a detached signature (false). + pub fn is_signed_msg(&self) -> Result { + match self.signature_type { + SignatureType::SignedMessage => Ok(true), + SignatureType::DetachedSignature => Ok(false), + _ => Err(SigningErr::SignatureVerificationFailed), + } + } +} + +/// Trait for setting cryptographic mechanisms. +pub trait MechanismSetter { + fn set_public_key(&mut self, public_key: Vec) -> Result<(), SigningErr>; + fn set_secret_key(&mut self, secret_key: Vec) -> Result<(), SigningErr>; + fn set_signed_msg(&mut self, signed_message: Vec) -> Result<(), SigningErr>; + fn set_signature(&mut self, detached_signature: Vec) -> Result<(), SigningErr>; +} + +/// Defines functionality for cryptographic mechanisms. +pub trait Mechanism { + fn keypair() -> Self; + + fn save_signed_msg(&self, path: PathBuf) -> Result<(), SigningErr>; + fn save_detached(&self, path: PathBuf) -> Result<(), SigningErr>; + + fn sign_msg(&mut self) -> Result, SigningErr>; + fn sign_detached(&mut self) -> Result, SigningErr>; + + fn verify_msg(&mut self) -> Result, SigningErr>; + fn verify_detached(&mut self) -> Result; +} + +impl MechanismSetter for SignatureKey { + /// Sets the public key for the signature. + fn set_public_key(&mut self, public_key: Vec) -> Result<(), SigningErr> { + self.data = public_key; + self.key_type = SignatureDataType::PublicKey; + Ok(()) + } + /// Sets the secret key for the signature. + fn set_secret_key(&mut self, secret_key: Vec) -> Result<(), SigningErr> { + self.data = secret_key; + self.key_type = SignatureDataType::SecretKey; + Ok(()) + } + /// Sets the signed message. + fn set_signed_msg(&mut self, signed_message: Vec) -> Result<(), SigningErr> { + self.data = signed_message; + self.key_type = SignatureDataType::SignedMessage; + Ok(()) + } + /// Sets the detached signature. + fn set_signature(&mut self, detached_signature: Vec) -> Result<(), SigningErr> { + self.data = detached_signature; + self.key_type = SignatureDataType::DetachedSignature; + Ok(()) + } +} +impl SignatureKey { + /// Constructs a new `SignatureKey`. + fn new() -> Self { + Self { + data: Vec::new(), key_type: SignatureDataType::None + } + } + /// Sets and gets the public key. + fn public_key(&mut self) -> Result<&[u8], SigningErr> { + self.key_type = SignatureDataType::PublicKey; + Ok(&self.data) + } + /// Sets and gets the secret key. + fn secret_key(&mut self) -> Result<&[u8], SigningErr> { + self.key_type = SignatureDataType::SecretKey; + Ok(&self.data) + } + /// Sets and gets the signed message. + fn signed_msg(&mut self) -> Result<&[u8], SigningErr> { + self.key_type = SignatureDataType::SignedMessage; + Ok(&self.data) + } + /// Sets and gets the detached signature. + fn signature(&mut self) -> Result<&[u8], SigningErr> { + self.key_type = SignatureDataType::DetachedSignature; + Ok(&self.data) + } +} \ No newline at end of file diff --git a/src/cryptography/hmac_sign/sign.rs b/src/cryptography/hmac_sign/sign.rs new file mode 100644 index 0000000..8665166 --- /dev/null +++ b/src/cryptography/hmac_sign/sign.rs @@ -0,0 +1,139 @@ +use super::*; +use crate::error::SigningErr; + +use hmac::{Hmac, Mac}; +use sha2::{Sha512, Sha256}; +use crate::{cryptography::*, error::*}; + +/// Represents a cryptographic signing operation, including data, passphrase, operational status, +/// hash type, signature length, and verification status. +impl Sign { + /// Constructs a new `Sign` instance with specified data, passphrase, operation status, and hash type. + /// + /// # Parameters + /// - `data`: The data to be signed or verified. + /// - `passphrase`: The passphrase used for HMAC generation. + /// - `status`: The operation status (signing or verifying). + /// - `hash_type`: The hash algorithm to use for signing. + /// + /// # Returns + /// A new `Sign` instance. + pub fn new(data: Vec, passphrase: Vec, status: Operation, hash_type: SignType) -> Self { + let data = SignatureData { + data, passphrase, hmac: Vec::new(), concat_data: Vec::new() + }; + match hash_type { + SignType::Sha512 => Sign { data, status, hash_type, length: 64, veryfied: false}, + SignType::Sha256 => Sign { data, status, hash_type, length: 32, veryfied: false}, + _ => Sign { data, status, hash_type, length: 64, veryfied: false}, + } + } + + /// Performs the HMAC operation based on the operation status: generates HMAC for signing + /// or verifies HMAC for verification. + /// + /// # Returns + /// HMAC as a `Vec` for signing or the verified data for verification. + pub fn hmac(&mut self) -> Vec { + match &self.status { + Operation::Sign => { + let data = self.generate_hmac(); + data + }, + Operation::Verify => { + let data = self.verify_hmac(); + data.unwrap() + }, + _ => vec![], + } + } + + /// Generates HMAC for the data using the specified hash type and passphrase. + /// + /// # Returns + /// Concatenated original data and its HMAC as a `Vec`. + pub fn generate_hmac(&self) -> Vec { + let mut data = &self.data.data; + match &self.hash_type { + SignType::Sha512 => { + let mut mac = as Mac>::new_from_slice(&self.data.passphrase) + .expect("HMAC can take key of any size"); + mac.update(&data); + let hmac = mac.finalize().into_bytes().to_vec(); + //println!("HMAC: {:?}", hmac); + let concat_data = [&self.data.data, hmac.as_slice()].concat(); + //println!("Concated data: {:?}", concat_data); + concat_data + }, + SignType::Sha256 => { + let mut mac = as Mac>::new_from_slice(&self.data.passphrase) + .expect("HMAC can take key of any size"); + mac.update(&data); + let hmac = mac.finalize().into_bytes().to_vec(); + println!("HMAC: {:?}", hmac); + let concat_data = [&self.data.data, hmac.as_slice()].concat(); + println!("Concated data: {:?}", concat_data); + concat_data + }, + _ => vec![], + } + } + + /// Verifies HMAC using SHA-512. + /// + /// # Parameters + /// - `data`: The data part of the message. + /// - `hmac`: The HMAC to verify against. + /// - `passphrase`: The passphrase used for HMAC generation. + /// + /// # Returns + /// `true` if verification is successful, `false` otherwise. + fn verify_hmac_sha512(data: &[u8], hmac: &[u8], passphrase: &[u8]) -> bool { + let mut mac = as Mac>::new_from_slice(passphrase) + .expect("HMAC can take key of any size"); + mac.update(data); + mac.verify_slice(hmac).is_ok() + } + + /// Verifies HMAC using SHA-256. + /// + /// # Parameters + /// - `data`: The data part of the message. + /// - `hmac`: The HMAC to verify against. + /// - `passphrase`: The passphrase used for HMAC generation. + /// + /// # Returns + /// `true` if verification is successful, `false` otherwise. + fn verify_hmac_sha256(data: &[u8], hmac: &[u8], passphrase: &[u8]) -> bool { + let mut mac = as Mac>::new_from_slice(passphrase) + .expect("HMAC can take key of any size"); + mac.update(data); + mac.verify_slice(hmac).is_ok() + } + + /// Verifies HMAC based on the hash type. Splits the provided data into the original data + /// and HMAC, then verifies the HMAC. + /// + /// # Returns + /// `Ok(Vec)` containing the original data if verification is successful, `Err(&'static str)` otherwise. + pub fn verify_hmac(&self) -> Result, &'static str> { + if self.data.data.len() < self.length { + return Err("Data is too short for HMAC verification"); + } + + let (data, hmac) = self.data.data.split_at(self.data.data.len() - self.length); + + let verification_success = match &self.hash_type { + SignType::Sha512 => Self::verify_hmac_sha512(data, hmac, &self.data.passphrase), + SignType::Sha256 => Self::verify_hmac_sha256(data, hmac, &self.data.passphrase), + _ => return Err("Unsupported HMAC hash type"), + }; + + if verification_success { + println!("splittet data: {:?}", data); + Ok(data.to_owned()) + } else { + Err("HMAC verification failed") + } + } +} \ No newline at end of file diff --git a/src/cryptography/mod.rs b/src/cryptography/mod.rs new file mode 100644 index 0000000..9a6bffd --- /dev/null +++ b/src/cryptography/mod.rs @@ -0,0 +1,150 @@ + /// The `hmac` module provides functionality for generating, managing, and verifying digital hmacs, supporting various algorithms including post-quantum secure schemes. +pub mod hmac_sign; + +/// The `cryptographic` module encapsulates core cryptographic operations, including key management, encryption, decryption, and cryptographic utility functions. +mod cryptographic; + +//pub use cipher_aes::*; +//pub use cipher_xchacha::*; +pub use cryptographic::*; +use std::path::PathBuf; +use crate::{error::CryptError, FileMetadata, Key}; +use std::fmt; + +/// Represents the AES cipher for encryption and decryption processes. +/// It holds cryptographic information and a shared secret for operations. +#[derive(PartialEq, Debug, Clone)] +pub struct CipherAES { + pub infos: CryptographicInformation, + pub sharedsecret: Vec, +} + +impl fmt::Display for CipherAES { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "CipherAES with the following Cryptographic Informations: {}", self.infos.metadata) + } +} + +/// Represents the ChaCha cipher for encryption and decryption processes. +/// It includes cryptographic information, a nonce for the operation, and a shared secret. +#[derive(PartialEq, Debug, Clone)] +pub struct CipherChaCha { + pub infos: CryptographicInformation, + pub nonce: [u8; 24], + pub sharedsecret: Vec, +} + +impl fmt::Display for CipherChaCha { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "CipherChaCha with the following Cryptographic Informations {}", self.infos.metadata) + } +} + +/// Enumerates the cryptographic mechanisms supported, such as AES and XChaCha20. +#[derive(PartialEq, Debug, Copy, Clone)] +pub enum CryptographicMechanism { + AES, + XChaCha20, +} + +impl fmt::Display for CryptographicMechanism { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let mechanism = match self { + CryptographicMechanism::AES => "AES", + CryptographicMechanism::XChaCha20 => "XChaCha20", + }; + write!(f, "{}", mechanism) + } +} + +/// Enumerates the key encapsulation mechanisms supported, such as Kyber1024. +#[derive(PartialEq, Debug, Copy, Clone)] +pub enum KeyEncapMechanism { + Kyber1024, + Kyber768, + Kyber512, +} + + +impl fmt::Display for KeyEncapMechanism { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let mechanism = match self { + KeyEncapMechanism::Kyber1024 => "Kyber1024", + KeyEncapMechanism::Kyber768 => "Kyber768", + KeyEncapMechanism::Kyber512 => "Kyber512", + }; + write!(f, "{}", mechanism) + } +} + +/// Enumerates the types of content that can be encrypted or decrypted, such as messages or files. +#[derive(PartialEq, Debug, Copy, Clone)] +pub enum ContentType { + Message, + File, +} + +impl fmt::Display for ContentType { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let content_type = match self { + ContentType::Message => "Message", + ContentType::File => "File", + }; + write!(f, "{}", content_type) + } +} + +/// Enumerates the cryptographic processes, such as encryption and decryption. +#[derive(PartialEq, Debug, Copy, Clone)] +pub enum Process { + Encryption, + Decryption, +} + +impl fmt::Display for Process { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let process = match self { + Process::Encryption => "Encryption", + Process::Decryption => "Decryption", + }; + write!(f, "{}", process) + } +} + +/// Holds metadata for cryptographic operations, specifying the process, encryption type, +/// key encapsulation mechanism, and content type. +#[derive(PartialEq, Debug, Copy, Clone)] +pub struct CryptographicMetadata { + pub process: Process, + pub encryption_type: CryptographicMechanism, + pub key_type: KeyEncapMechanism, + pub content_type: ContentType, +} + +impl fmt::Display for CryptographicMetadata { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "Process: {}\nEncryption Type: {}\nKey Type: {}\nContent Type: {}", self.process, self.encryption_type, self.key_type, self.content_type) + } +} + +/// Contains information necessary for performing cryptographic operations, including the content +/// to be encrypted or decrypted, a passphrase, metadata defining the operation context, and a flag +/// indicating whether the content should be saved securely. +#[derive(PartialEq, Debug, Clone)] +pub struct CryptographicInformation { + pub content: Vec, + pub passphrase: Vec, + pub metadata: CryptographicMetadata, + pub safe: bool, + pub location: Option, +} + +impl fmt::Display for CryptographicInformation { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "Cryptographic Information:\n\ + -\tMetadata:\t\t{}\n\ + -\tContent Length:\t{} bytes\n", + self.metadata, + self.content.len()) + } +} diff --git a/src/error.rs b/src/error.rs new file mode 100644 index 0000000..ad9dc39 --- /dev/null +++ b/src/error.rs @@ -0,0 +1,151 @@ +use std::{fmt::{self, Display, Formatter}, error::Error, io, }; + +#[derive(Debug, Clone)] +pub enum CryptError { + IOError(String), + MessageExtractionError, + InvalidMessageFormat, + HexError(hex::FromHexError), + EncapsulationError, + DecapsulationError, + WriteError, + HmacVerificationError, + HmacShortData, + HmacKeyErr, + HexDecodingError(String), + UniqueFilenameFailed, + MissingSecretKey, + MissingPublicKey, + MissingCiphertext, + MissingSharedSecret, + MissingData, + InvalidParameters, + PathError, + Utf8Error, + SigningFailed, + SignatureVerificationFailed, + InvalidSignatureLength, + InvalidSignature, + InvalidDataLength, + UnsupportedOperation, + InvalidKeyType, + FileNotFound, + EncryptionFailed, + CustomError(String), +} + +impl fmt::Display for CryptError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + CryptError::IOError(message) => write!(f, "IO error: {:?}", message), + CryptError::MessageExtractionError => write!(f, "Error extracting message"), + CryptError::InvalidMessageFormat => write!(f, "Invalid message format"), + CryptError::HexError(err) => write!(f, "Hex error: {}", err), + CryptError::EncapsulationError => write!(f, "Encapsulation error"), + CryptError::DecapsulationError => write!(f, "Decapsulation error"), + CryptError::WriteError => write!(f, "Write error"), + CryptError::HmacVerificationError => write!(f, "HMAC verification error"), + CryptError::HmacShortData => write!(f, "Data is too short for HMAC verification"), + CryptError::HmacKeyErr => write!(f, "HMAC can take key of any size"), + CryptError::HexDecodingError(err) => write!(f, "Hex decoding error: {}", err), + CryptError::UniqueFilenameFailed => write!(f, "Unique filename failed"), + CryptError::MissingSecretKey => write!(f, "Missing secret key"), + CryptError::MissingPublicKey => write!(f, "Missing public key"), + CryptError::MissingCiphertext => write!(f, "Missing ciphertext"), + CryptError::MissingSharedSecret => write!(f, "Missing shared secret"), + CryptError::MissingData => write!(f, "Missing data"), + CryptError::InvalidParameters => write!(f, "You provided Invalid parameters"), + CryptError::PathError => write!(f, "The provided path does not exist!"), + CryptError::Utf8Error => write!(f, "UTF-8 conversion error"), + CryptError::SigningFailed => write!(f, "Signing file using falcon 1024 failed!"), + CryptError::SignatureVerificationFailed => write!(f, "verification of signature using falcon 1024 failed!"), + CryptError::InvalidSignature => write!(f, "Signature not valid!"), + CryptError::InvalidSignatureLength => write!(f, "Data is too short for HMAC verification"), + CryptError::InvalidDataLength => write!(f, "Data size of encrypted data isn't multiple of the block size!"), + CryptError::UnsupportedOperation => write!(f, "Unsupported operation"), + CryptError::InvalidKeyType => write!(f, "Invalid or unsupported key type"), + CryptError::FileNotFound => write!(f, "The selected file was not found, either look in amother folder or check if you have correctly written the file name!"), + CryptError::EncryptionFailed => write!(f, "There occurred an error for some reason, please chek the implementation again and make sure everything was used correctly, for more info use: RUST_BACKTRACE=[1 or full]!"), + CryptError::CustomError(message) => write!(f, "{}", message), + } + } +} + +impl CryptError { + // `new` method for creating a CryptError with a custom message + pub fn new(msg: &str) -> Self { + CryptError::CustomError(msg.to_owned()) + } +} + +impl From for CryptError { + fn from(error: std::io::Error) -> Self { + // Here, you might want to match on the error kind to provide more specific error variants if applicable + // For a simple catch-all conversion, you can use a general error variant from your CryptError enum + // Assume CryptError has a variant like IOError(String) for holding io::Error descriptions + CryptError::IOError(error.to_string()) + } +} + +impl Error for CryptError {} + +impl From for CryptError { + fn from(error: hex::FromHexError) -> Self { + CryptError::HexError(error) + } +} + +#[derive(Debug)] +pub enum SigningErr { + SecretKeyMissing, + PublicKeyMissing, + SignatureVerificationFailed, + SigningMessageFailed, + SignatureMissing, + FileCreationFailed, + FileWriteFailed, + IOError(io::Error), +} + +impl Display for SigningErr { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + match self { + SigningErr::SecretKeyMissing => write!(f, "Secret key is missing"), + SigningErr::PublicKeyMissing => write!(f, "Public key is missing"), + SigningErr::SignatureVerificationFailed => write!(f, "Signature verification failed"), + SigningErr::SigningMessageFailed => write!(f, "Failed to sign message"), + SigningErr::SignatureMissing => write!(f, "Signature is missing"), + SigningErr::FileCreationFailed => write!(f, "Failed to create file"), + SigningErr::FileWriteFailed => write!(f, "Failed to write to file"), + SigningErr::IOError(err) => write!(f, "IOError occurred: {}", err), + } + } +} + +impl PartialEq for SigningErr { + fn eq(&self, other: &Self) -> bool { + use SigningErr::*; + match (self, other) { + (SecretKeyMissing, SecretKeyMissing) + | (PublicKeyMissing, PublicKeyMissing) + | (SignatureVerificationFailed, SignatureVerificationFailed) + | (SigningMessageFailed, SigningMessageFailed) => true, + (IOError(_), IOError(_)) => false, + _ => false, + } + } +} + +impl From for SigningErr { + fn from(_: pqcrypto_traits::Error) -> Self { + SigningErr::SignatureVerificationFailed + } +} + +impl Error for SigningErr {} + +impl From for SigningErr { + fn from(err: io::Error) -> Self { + SigningErr::IOError(err) + } +} \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..3c0eacd --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,93 @@ +#[macro_use] +extern crate lazy_static; + +/// Core functionalitys for control of Kyber keys as well as encryption and decryption +mod Core; +/// Cryptographic related functionalitys, enums structs and modules +mod cryptography; +/// File and Key related functionalitys, enums structs and modules +mod KeyControl; +/// Logging related functionalitys +pub mod log; +/// Error types +pub mod error; + +#[cfg(test)] +mod tests; + +pub use crate::{ + log::*, + Core::KDF, + KeyControl::{ + *, + file::*, + }, + Core::{ + *, + kyber::{ + *, + KeyKyber::{self, *}, + }, + }, + cryptography::{ + *, + }, + +}; + +use KeyControl::*; +use cryptography::*; + + +use pqcrypto_falcon::falcon1024::{self, *}; +use pqcrypto_kyber::kyber1024::{self, *}; +use std::{ + error::Error, + fmt::{self, *}, + iter::repeat, + path::{PathBuf, Path}, + marker::PhantomData, + result::Result, + io::{Read, Write}, + sync::Mutex, + fs +}; + +lazy_static! { + static ref LOGGER: Mutex = Mutex::new(Log { + activated: false, // Initially deactivated; activate it as needed. + log: String::new(), + location: None, + }); +} + +pub fn activate_log>(log_file: P) { + let mut logger = LOGGER.lock().unwrap(); + logger.activated = true; + logger.location = Some(log_file.as_ref().to_path_buf()); +} + +#[macro_export] +macro_rules! log_activity { + ($process:expr, $kyber_size:expr) => { + match LOGGER.lock() { + Ok(mut logger) => { + let _ = logger.append_log($process, $kyber_size); + }, + Err(e) => eprintln!("Logger lock error: {}", e), + } + }; +} + +#[macro_export] +macro_rules! write_log { + () => { + { + let mut logger = $crate::LOGGER.lock().expect("Logger lock failed"); + if let Err(e) = logger.write_log_file() { + eprintln!("Failed to write log file: {:?}", e); + } + logger.log.clear(); // Clear the log after writing + } + }; +} \ No newline at end of file diff --git a/src/log.rs b/src/log.rs new file mode 100644 index 0000000..79bb681 --- /dev/null +++ b/src/log.rs @@ -0,0 +1,91 @@ +use std::{ + path::{PathBuf, Path}, + marker::PhantomData, + result::Result, + io::{Read, Write}, + fs::{self, OpenOptions} +}; +use chrono::{Local, NaiveDateTime}; +use crate::error::CryptError; + +/// Struct used for logging +pub struct Log { + pub activated: bool, + pub log: String, + pub location: Option, +} + +impl Log { + /// Activate the log and define the log files path. + pub fn activate(log_file: PathBuf) -> Self { + Log { + activated: true, + log: String::new(), + location: Some(log_file), + } + } + /// Clear the structs String element. + pub fn clear(&mut self) { + self.log.clear(); + } + /// Append two &str to the log. When manually impementing it please regard that the format used is: + /// "{}:\n\t{}{}\n", process(&str), detail(&str) + pub fn append_log(&mut self, process: &str, detail: &str) -> Result<(), CryptError> { + if self.activated { + let timestamp = Local::now(); + let log_entry = format!("{}:\n\t{}{}\n", timestamp.format("%m/%d/%y %H:%M"), process, detail); + + // Prepend a newline to the log entry if the log is not empty + let log_entry: String = if !self.log.is_empty() { + format!("\n{}", log_entry) + } else { + log_entry + }; + + self.log.push_str(&log_entry); + + if let Some(ref location) = self.location { + let mut file = OpenOptions::new() + .create(true) + .write(true) + .append(true) + .open(location)?; + writeln!(file, "{}", log_entry)?; + } + } + Ok(()) + } + /// Create a new splitted log file + pub fn write_log_file(&mut self) -> Result<(), CryptError> { + if !self.activated { + return Err(CryptError::CustomError("Logger is not activated.".to_string())); + } + if let Some(ref location) = self.location { + let parent_dir = location.parent().unwrap_or_else(|| Path::new("")); + let file_stem = location.file_stem().unwrap().to_str().unwrap(); + let extension = location.extension().unwrap_or_default().to_str().unwrap(); + + let log_dir = parent_dir.join(file_stem); + if !log_dir.exists() { + fs::create_dir_all(&log_dir).map_err(|e| CryptError::IOError(e.to_string()))?; + } + + let mut file_path = log_dir.join(format!("{}.{}", file_stem, extension)); + let mut counter = 1; + while file_path.exists() { + file_path = log_dir.join(format!("{}_{}.{}", file_stem, counter, extension)); + counter += 1; + } + + let mut file = OpenOptions::new().create(true).write(true).open(file_path)?; + write!(file, "{}", self.log)?; + + // Clear the log content after writing to file + self.log.clear(); + } else { + return Err(CryptError::CustomError("Log location not set.".to_string())); + } + + Ok(()) + } +} \ No newline at end of file diff --git a/src/tests/KyberKeyTest.rs b/src/tests/KyberKeyTest.rs new file mode 100644 index 0000000..dc7e758 --- /dev/null +++ b/src/tests/KyberKeyTest.rs @@ -0,0 +1,160 @@ +use super::*; +use crate::error::CryptError; +use std::{ + fs::{self, File}, + io::{Read, self}, + path::{PathBuf, Path}, +}; +use crate::{ + hmac_sign::*, + KeyControKyber1024, + KeyControKyber512, + KeyControKyber768, + Core::KeyControl, + KyberKeyFunctions, + KeyTypes, + FileTypes, + FileMetadata, + FileState, +}; + +use tempfile::{TempDir, Builder, tempdir}; + +fn test_keypair_generation() { + let (public_key, secret_key) = T::keypair().expect("Key pair generation failed"); + assert!(!public_key.is_empty(), "Public key is empty"); + assert!(!secret_key.is_empty(), "Secret key is empty"); +} + +#[test] +fn keypair_generation_kyber1024() { + test_keypair_generation::(); +} + +#[test] +fn keypair_generation_kyber768() { + test_keypair_generation::(); +} + +#[test] +fn keypair_generation_kyber512() { + test_keypair_generation::(); +} + +// Tests encapsulation and decapsulation using the generated keys +fn test_encap_decap() { + let (public_key, secret_key) = T::keypair().unwrap(); + let (shared_secret_encap, ciphertext) = T::encap(&public_key).unwrap(); + let shared_secret_decap = T::decap(&secret_key, &ciphertext).unwrap(); + + assert_eq!(shared_secret_encap, shared_secret_decap, "Shared secrets do not match"); +} + +#[test] +fn encap_decap_kyber1024() { + test_encap_decap::(); +} + +#[test] +fn encap_decap_kyber768() { + test_encap_decap::(); +} + +#[test] +fn encap_decap_kyber512() { + test_encap_decap::(); +} + +// Test the functionality of the KeyControl struct +#[test] +fn key_control_functionality() { + let base_path = PathBuf::from("/tmp"); // Example path, adjust as needed + let (public_key, secret_key) = KeyControKyber1024::keypair().expect(""); + let mut key_control = KeyControl::::new(); + let _ = key_control.set_public_key(public_key).unwrap(); + + // Use the public key from KeyControl to encapsulate + let (shared_secret, ciphertext) = key_control.encap(key_control.public_key().unwrap().as_slice()).unwrap(); + let _ = key_control.set_ciphertext(ciphertext).unwrap(); + // Use the secret key from KeyControl to decapsulate + let decrypted_shared_secret = key_control.decap(&secret_key, key_control.ciphertext().unwrap().as_slice()).unwrap(); + + assert_eq!(shared_secret, decrypted_shared_secret, "Shared secrets do not match after KeyControl operations"); +} + +// Helper function to read a file into a Vec +fn read_file(path: &PathBuf) -> Result, std::io::Error> { + let mut file = fs::File::open(path)?; + let mut contents = vec![]; + file.read_to_end(&mut contents)?; + Ok(contents) +} + +#[test] +fn test_key_control_safe_functionality() -> Result<(), Box> { + // Generate a keypair + let (public_key, secret_key) = KeyControKyber1024::keypair().unwrap(); + + // Encapsulate a secret with the public key + let (shared_secret, ciphertext) = KeyControKyber1024::encap(&public_key).unwrap(); + + // Initialize KeyControl and set keys + let mut key_control = KeyControl::::new(); + // key_control.set_public_key(pqcrypto_traits::kem::PublicKey::from_bytes(public_key.clone()).as_bytes().to_owned()).unwrap(); + key_control.set_public_key(public_key.clone()).unwrap(); + key_control.save(KeyTypes::PublicKey, "./key".into()).unwrap(); + + key_control.set_secret_key(secret_key.clone()).unwrap(); + key_control.save(KeyTypes::SecretKey, "./key".into()).unwrap(); + + key_control.set_ciphertext(ciphertext.clone()).unwrap(); + key_control.save(KeyTypes::Ciphertext, "./key".into()).unwrap(); + + let cipher = key_control.load(KeyTypes::Ciphertext, Path::new("./key/ciphertext.ct")); + let pubk = key_control.load(KeyTypes::PublicKey, Path::new("./key/public_key.pub")); + let seck = key_control.load(KeyTypes::SecretKey, Path::new("./key/secret_key.sec")); + + // Verify the integrity of the saved keys + assert!(Path::new("./key/ciphertext.ct").exists()); + assert!(Path::new("./key/public_key.pub").exists()); + assert!(Path::new("./key/secret_key.sec").exists()); + assert_eq!(&public_key.len(), &pubk.clone()?.len()); + assert_eq!(public_key, pubk?, "Public keys do not match"); + assert_eq!(secret_key, seck?, "Secret keys do not match"); + assert_eq!(ciphertext, cipher?, "Ciphertexts do not match"); + + fs::remove_dir_all("./key")?; + Ok(()) +} + +#[test] +fn test_key() { + let (public_key, secret_key) = KeyControKyber1024::keypair().unwrap(); + + let keycontrol = KeyControl::::new(); + + let pubkey_file = FileMetadata::from( + PathBuf::from("key.pub"), + FileTypes::PublicKey, + FileState::Other + ); + let seckey_file = FileMetadata::from( + PathBuf::from("key.sec"), + FileTypes::SecretKey, + FileState::Other + ); + + + let _ = pubkey_file.save(&public_key); + let _ = seckey_file.save(&secret_key); + + let public_key2 = keycontrol.load(KeyTypes::PublicKey, &Path::new("key.pub")).unwrap(); + let secret_key2 = keycontrol.load(KeyTypes::SecretKey, &Path::new("key.sec")).unwrap(); + + assert_eq!(public_key2, public_key); + assert_eq!(secret_key2, secret_key); + + + fs::remove_file(Path::new("key.pub")); + fs::remove_file(Path::new("key.sec")); +} diff --git a/src/tests/LoggingTests.rs b/src/tests/LoggingTests.rs new file mode 100644 index 0000000..8f43998 --- /dev/null +++ b/src/tests/LoggingTests.rs @@ -0,0 +1,58 @@ +use std::fs::{self, File}; +use std::io::Read; +use tempfile::tempdir; +use crate::{log::*, log_activity, write_log, activate_log, LOGGER}; + +#[test] +fn test_logger_activation() { + let log_dir = tempdir().unwrap(); + let log_file_path = log_dir.path().join("test_log.txt"); + + // Activate the logger with a temporary directory + activate_log(log_file_path.to_str().unwrap()); + + // Your logic to verify logger activation + // For example, check if the `activated` flag is set to true, which might require making the flag accessible or checking for side effects of activation. +} + +#[test] +fn test_log_directory_creation() { + let log_dir = tempdir().unwrap(); + let log_file_path = log_dir.path().join("test_log.txt"); + + activate_log(log_file_path.to_str().unwrap()); + log_activity!("Test log entry", "\nSeccond part"); // Use the macro to generate a log entry + write_log!(); // Attempt to write the log file + + // Verify the log directory and file are created correctly + assert!(log_dir.path().join("test_log").exists(), "Log directory should exist"); +} + +#[test] +fn test_unique_log_file_naming() { + let log_dir = tempdir().unwrap(); + let log_file_path = log_dir.path().join("test_log.txt"); + + activate_log(log_file_path.to_str().unwrap()); + + // Generate and write multiple log entries to ensure unique naming + for _ in 0..3 { + log_activity!("Test log entry", "\nSeccond part"); + write_log!(); + } + + let log_files = fs::read_dir(log_dir.path().join("test_log")).unwrap(); + + // Ensure that there are exactly 3 log files with expected naming pattern + let mut file_count = 0; + for entry in log_files { + let entry = entry.unwrap(); + let path = entry.path(); + let filename = path.file_name().unwrap().to_str().unwrap(); + + assert!(filename.starts_with("test_log_") || filename == "test_log.txt", "Unexpected file name: {}", filename); + file_count += 1; + } + + assert_eq!(file_count, 3, "There should be exactly 3 log files"); +} \ No newline at end of file diff --git a/src/tests/SignatureTests.rs b/src/tests/SignatureTests.rs new file mode 100644 index 0000000..044a76e --- /dev/null +++ b/src/tests/SignatureTests.rs @@ -0,0 +1,175 @@ +use super::*; +use crate::KDF::*; + +#[test] +fn test_falcon1024_signature_message() -> Result<(), Box> { + let (public_key, secret_key) = Falcon1024::keypair().unwrap(); + let data = b"Hello, world!".to_vec(); + let sign = Signature::::new(); + // Sign the message + let signed_message = sign.signature(data.clone(), secret_key)?; + + // Open the message + let opened_message = sign.open(signed_message, public_key)?; + + // Verify the opened message matches the original data + assert_eq!(data, opened_message); + Ok(()) +} + + +#[test] +fn test_falcon1024_detached_signature() -> Result<(), Box> { + let (public_key, secret_key) = Falcon1024::keypair().unwrap(); + let data = b"Hello, world!".to_vec(); + + let sign = Signature::::new(); + + // Create a detached signature + let signature = sign.signature(data.clone(), secret_key)?; + + // Verify the detached signature + let is_valid = sign.verify(data, signature, public_key)?; + + assert!(is_valid); + Ok(()) +} + +#[test] +fn test_falcon512_signature_message() -> Result<(), Box> { + let (public_key, secret_key) = Falcon512::keypair().unwrap(); + let data = b"Hello, world!".to_vec(); + let sign = Signature::::new(); + // Sign the message + let signed_message = sign.signature(data.clone(), secret_key)?; + + // Open the message + let opened_message = sign.open(signed_message, public_key)?; + + // Verify the opened message matches the original data + assert_eq!(data, opened_message); + Ok(()) +} + + +#[test] +fn test_falcon512_detached_signature() -> Result<(), Box> { + let (public_key, secret_key) = Falcon512::keypair().unwrap(); + let data = b"Hello, world!".to_vec(); + + let sign = Signature::::new(); + + // Create a detached signature + let signature = sign.signature(data.clone(), secret_key)?; + + // Verify the detached signature + let is_valid = sign.verify(data, signature, public_key)?; + + assert!(is_valid); + Ok(()) +} + + +#[test] +fn test_dilithium2_signature_message() -> Result<(), Box> { + let (public_key, secret_key) = Dilithium2::keypair().unwrap(); + let data = b"Hello, world!".to_vec(); + let sign = Signature::::new(); + // Sign the message + let signed_message = sign.signature(data.clone(), secret_key)?; + + // Open the message + let opened_message = sign.open(signed_message, public_key)?; + + // Verify the opened message matches the original data + assert_eq!(data, opened_message); + Ok(()) +} + + +#[test] +fn test_dilithium2_detached_signature() -> Result<(), Box> { + let (public_key, secret_key) = Dilithium2::keypair().unwrap(); + let data = b"Hello, world!".to_vec(); + + let sign = Signature::::new(); + + // Create a detached signature + let signature = sign.signature(data.clone(), secret_key)?; + + // Verify the detached signature + let is_valid = sign.verify(data, signature, public_key)?; + + assert!(is_valid); + Ok(()) +} + + +#[test] +fn test_dilithium3_signature_message() -> Result<(), Box> { + let (public_key, secret_key) = Dilithium3::keypair().unwrap(); + let data = b"Hello, world!".to_vec(); + let sign = Signature::::new(); + // Sign the message + let signed_message = sign.signature(data.clone(), secret_key)?; + + // Open the message + let opened_message = sign.open(signed_message, public_key)?; + + // Verify the opened message matches the original data + assert_eq!(data, opened_message); + Ok(()) +} + + +#[test] +fn test_dilithium3_detached_signature() -> Result<(), Box> { + let (public_key, secret_key) = Dilithium3::keypair().unwrap(); + let data = b"Hello, world!".to_vec(); + + let sign = Signature::::new(); + + // Create a detached signature + let signature = sign.signature(data.clone(), secret_key)?; + + // Verify the detached signature + let is_valid = sign.verify(data, signature, public_key)?; + + assert!(is_valid); + Ok(()) +} + + +#[test] +fn test_dilithium5_signature_message() -> Result<(), Box> { + let (public_key, secret_key) = Dilithium5::keypair().unwrap(); + let data = b"Hello, world!".to_vec(); + let sign = Signature::::new(); + // Sign the message + let signed_message = sign.signature(data.clone(), secret_key)?; + + // Open the message + let opened_message = sign.open(signed_message, public_key)?; + + // Verify the opened message matches the original data + assert_eq!(data, opened_message); + Ok(()) +} + + +#[test] +fn test_dilithium5_detached_signature() -> Result<(), Box> { + let (public_key, secret_key) = Dilithium5::keypair().unwrap(); + let data = b"Hello, world!".to_vec(); + + let sign = Signature::::new(); + + // Create a detached signature + let signature = sign.signature(data.clone(), secret_key)?; + + // Verify the detached signature + let is_valid = sign.verify(data, signature, public_key)?; + + assert!(is_valid); + Ok(()) +} \ No newline at end of file diff --git a/src/tests/kyber_tests.rs b/src/tests/kyber_tests.rs new file mode 100644 index 0000000..9a2c627 --- /dev/null +++ b/src/tests/kyber_tests.rs @@ -0,0 +1,450 @@ +use super::*; +use std::io::{Read, Write}; +use tempfile::{TempDir, Builder}; +use std::fs::{self, File}; +use std::marker::PhantomData; +use crate::{ + Core::{kyber::{KyberFunctions, *}, *}, + error::* +}; + +#[test] +fn encrypt_message_AES_Kyber1024() -> Result<(), Box> { + let message = "Hey, how are you doing?"; + let passphrase = "Test Passphrase"; + + // Generate key pair + let (public_key, secret_key) = KeyControKyber1024::keypair().expect("Failed to generate keypair"); + + // Instantiate Kyber for encryption with Kyber1024 + let mut encryptor = Kyber::::new(public_key.clone(), None)?; + + // Encrypt message + let (encrypt_message, cipher) = encryptor.encrypt_msg(message.clone(), passphrase.clone())?; + + // Instantiate Kyber for decryption with Kyber1024 + let mut decryptor = Kyber::::new(secret_key, None)?; + + // Decrypt message + let decrypt_message = decryptor.decrypt_msg(encrypt_message.clone(), passphrase.clone(), cipher)?; + + // Convert Vec to String for comparison + let decrypted_text = String::from_utf8(decrypt_message).expect("Failed to convert decrypted message to string"); + + // Assert that the decrypted message matches the original message + assert_eq!(decrypted_text, message); + + Ok(()) +} + +#[test] +fn encrypt_message_AES_Kyber768() -> Result<(), Box> { + let message = "Hey, how are you doing?"; + let passphrase = "Test Passphrase"; + + // Generate key pair + let (public_key, secret_key) = KeyControKyber768::keypair().expect("Failed to generate keypair"); + + // Instantiate Kyber for encryption with Kyber768 + let mut encryptor = Kyber::::new(public_key.clone(), None)?; + + // Encrypt message + let (encrypt_message, cipher) = encryptor.encrypt_msg(message.clone(), passphrase.clone())?; + + // Instantiate Kyber for decryption with Kyber768 + let mut decryptor = Kyber::::new(secret_key, None)?; + + // Decrypt message + let decrypt_message = decryptor.decrypt_msg(encrypt_message.clone(), passphrase.clone(), cipher)?; + + // Convert Vec to String for comparison + let decrypted_text = String::from_utf8(decrypt_message).expect("Failed to convert decrypted message to string"); + + // Assert that the decrypted message matches the original message + assert_eq!(decrypted_text, message); + + Ok(()) +} + +fn encrypt_message_AES_Kyber512() -> Result<(), Box> { + let message = "Hey, how are you doing?"; + let passphrase = "Test Passphrase"; + + // Generate key pair + let (public_key, secret_key) = KeyControKyber512::keypair().expect("Failed to generate keypair"); + + // Instantiate Kyber for encryption with Kyber512 + let mut encryptor = Kyber::::new(public_key.clone(), None)?; + + // Encrypt message + let (encrypt_message, cipher) = encryptor.encrypt_msg(message.clone(), passphrase.clone())?; + + // Instantiate Kyber for decryption with Kyber512 + let mut decryptor = Kyber::::new(secret_key, None)?; + + // Decrypt message + let decrypt_message = decryptor.decrypt_msg(encrypt_message.clone(), passphrase.clone(), cipher)?; + + // Convert Vec to String for comparison + let decrypted_text = String::from_utf8(decrypt_message).expect("Failed to convert decrypted message to string"); + + // Assert that the decrypted message matches the original message + assert_eq!(decrypted_text, message); + + Ok(()) +} + +#[test] +fn encrypt_file_AES_Kyber1024() -> Result<(), Box> { + let message = "Hey, how are you doing?"; + + let tmp_dir = TempDir::new().map_err(|e| CryptError::from(e))?; + let tmp_dir = Builder::new().prefix("messages").tempdir().map_err(|e| CryptError::from(e))?; + + let enc_path = tmp_dir.path().clone().join("message.txt"); + let dec_path = tmp_dir.path().clone().join("message.txt.enc"); + + fs::write(&enc_path, message.as_bytes())?; + + let passphrase = "Test Passphrase"; + + // Generate key pair + let (public_key, secret_key) = KeyControKyber1024::keypair().expect("Failed to generate keypair"); + + // Instantiate Kyber for encryption with Kyber1024 + let mut encryptor = Kyber::::new(public_key.clone(), None)?; + + // Encrypt message + let (encrypt_message, cipher) = encryptor.encrypt_file(enc_path.clone(), passphrase.clone())?; + + fs::remove_file(enc_path.clone()); + + // Instantiate Kyber for decryption with Kyber1024 + let mut decryptor = Kyber::::new(secret_key, None)?; + + // Decrypt message + let decrypt_message = decryptor.decrypt_file(dec_path.clone(), passphrase.clone(), cipher)?; + + // Convert Vec to String for comparison + let decrypted_text = String::from_utf8(decrypt_message).expect("Failed to convert decrypted message to string"); + + // Assert that the decrypted message matches the original message + assert_eq!(decrypted_text, message.clone()); + + assert!(enc_path.exists(), "Decrypted file should exist after decryption."); + let decrypted_message = fs::read_to_string(&enc_path)?; + assert_eq!(decrypted_message, message, "Decrypted message should match the original message."); + + Ok(()) +} + +#[test] +fn encrypt_file_AES_Kyber768() -> Result<(), Box> { + let message = "Hey, how are you doing?"; + + let tmp_dir = TempDir::new().map_err(|e| CryptError::from(e))?; + let tmp_dir = Builder::new().prefix("messages").tempdir().map_err(|e| CryptError::from(e))?; + + let enc_path = tmp_dir.path().clone().join("message.txt"); + let dec_path = tmp_dir.path().clone().join("message.txt.enc"); + + fs::write(&enc_path, message.as_bytes())?; + + let passphrase = "Test Passphrase"; + + // Generate key pair + let (public_key, secret_key) = KeyControKyber768::keypair().expect("Failed to generate keypair"); + + // Instantiate Kyber for encryption with Kyber1024 + let mut encryptor = Kyber::::new(public_key.clone(), None)?; + + // Encrypt message + let (encrypt_message, cipher) = encryptor.encrypt_file(enc_path.clone(), passphrase.clone())?; + + fs::remove_file(enc_path.clone()); + + // Instantiate Kyber for decryption with Kyber1024 + let mut decryptor = Kyber::::new(secret_key, None)?; + + // Decrypt message + let decrypt_message = decryptor.decrypt_file(dec_path.clone(), passphrase.clone(), cipher)?; + + // Convert Vec to String for comparison + let decrypted_text = String::from_utf8(decrypt_message).expect("Failed to convert decrypted message to string"); + + // Assert that the decrypted message matches the original message + assert_eq!(decrypted_text, message.clone()); + + assert!(enc_path.exists(), "Decrypted file should exist after decryption."); + let decrypted_message = fs::read_to_string(&enc_path)?; + assert_eq!(decrypted_message, message, "Decrypted message should match the original message."); + + Ok(()) +} + + +#[test] +fn encrypt_file_AES_Kyber512() -> Result<(), Box> { + let message = "Hey, how are you doing?"; + + let tmp_dir = TempDir::new().map_err(|e| CryptError::from(e))?; + let tmp_dir = Builder::new().prefix("messages").tempdir().map_err(|e| CryptError::from(e))?; + + let enc_path = tmp_dir.path().clone().join("message.txt"); + let dec_path = tmp_dir.path().clone().join("message.txt.enc"); + + fs::write(&enc_path, message.as_bytes())?; + + let passphrase = "Test Passphrase"; + + // Generate key pair + let (public_key, secret_key) = KeyControKyber512::keypair().expect("Failed to generate keypair"); + + // Instantiate Kyber for encryption with Kyber512 + let mut encryptor = Kyber::::new(public_key.clone(), None)?; + + // Encrypt message + let (encrypt_message, cipher) = encryptor.encrypt_file(enc_path.clone(), passphrase.clone())?; + + fs::remove_file(enc_path.clone()); + + // Instantiate Kyber for decryption with Kyber512 + let mut decryptor = Kyber::::new(secret_key, None)?; + + // Decrypt message + let decrypt_message = decryptor.decrypt_file(dec_path.clone(), passphrase.clone(), cipher)?; + + // Convert Vec to String for comparison + let decrypted_text = String::from_utf8(decrypt_message).expect("Failed to convert decrypted message to string"); + + // Assert that the decrypted message matches the original message + assert_eq!(decrypted_text, message.clone()); + + assert!(enc_path.exists(), "Decrypted file should exist after decryption."); + let decrypted_message = fs::read_to_string(&enc_path)?; + assert_eq!(decrypted_message, message, "Decrypted message should match the original message."); + + Ok(()) +} + +#[test] +fn encrypt_message_XChaCha20_Kyber1024() -> Result<(), Box> { + let message = "Hey, how are you doing?"; + let passphrase = "Test Passphrase"; + + // Generate key pair + let (public_key, secret_key) = KeyControKyber1024::keypair().expect("Failed to generate keypair"); + + // Instantiate Kyber for encryption with Kyber1024 + let mut encryptor = Kyber::::new(public_key.clone(), None)?; + + // Encrypt message + let (encrypt_message, cipher) = encryptor.encrypt_msg(message.clone(), passphrase.clone())?; + + let nonce = encryptor.get_nonce(); + + // Instantiate Kyber for decryption with Kyber1024 + let mut decryptor = Kyber::::new(secret_key, Some(nonce?.to_string()))?; + + // Decrypt message + let decrypt_message = decryptor.decrypt_msg(encrypt_message.clone(), passphrase.clone(), cipher)?; + + // Assert that the decrypted message matches the original message + assert_eq!(String::from_utf8(decrypt_message).expect("Failed to convert decrypted message to string"), message); + + Ok(()) +} + +#[test] +fn encrypt_message_XChaCha20_Kyber768() -> Result<(), Box> { + let message = "Hey, how are you doing?"; + let passphrase = "Test Passphrase"; + + // Generate key pair + let (public_key, secret_key) = KeyControKyber768::keypair().expect("Failed to generate keypair"); + + // Instantiate Kyber for encryption with Kyber768 + let mut encryptor = Kyber::::new(public_key.clone(), None)?; + + // Encrypt message + let (encrypt_message, cipher) = encryptor.encrypt_msg(message.clone(), passphrase.clone())?; + + let nonce = encryptor.get_nonce(); + + // Instantiate Kyber for decryption with Kyber768 + let mut decryptor = Kyber::::new(secret_key, Some(nonce?.to_string()))?; + + // Decrypt message + let decrypt_message = decryptor.decrypt_msg(encrypt_message.clone(), passphrase.clone(), cipher)?; + + // Assert that the decrypted message matches the original message + assert_eq!(String::from_utf8(decrypt_message).expect("Failed to convert decrypted message to string"), message); + + Ok(()) +} + +#[test] +fn encrypt_message_XChaCha20_Kyber512() -> Result<(), Box> { + let message = "Hey, how are you doing?"; + let passphrase = "Test Passphrase"; + + // Generate key pair + let (public_key, secret_key) = KeyControKyber512::keypair().expect("Failed to generate keypair"); + + // Instantiate Kyber for encryption with Kyber512 + let mut encryptor = Kyber::::new(public_key.clone(), None)?; + + // Encrypt message + let (encrypt_message, cipher) = encryptor.encrypt_msg(message.clone(), passphrase.clone())?; + + let nonce = encryptor.get_nonce(); + + // Instantiate Kyber for decryption with Kyber512 + let mut decryptor = Kyber::::new(secret_key, Some(nonce?.to_string()))?; + + // Decrypt message + let decrypt_message = decryptor.decrypt_msg(encrypt_message.clone(), passphrase.clone(), cipher)?; + + // Assert that the decrypted message matches the original message + assert_eq!(String::from_utf8(decrypt_message).expect("Failed to convert decrypted message to string"), message); + + Ok(()) +} + +#[test] +fn encrypt_file_XChaCha20_Kyber1024() -> Result<(), Box> { + let message = "Hey, how are you doing?"; + + let tmp_dir = TempDir::new().map_err(|e| CryptError::from(e))?; + let tmp_dir = Builder::new().prefix("messages").tempdir().map_err(|e| CryptError::from(e))?; + + let enc_path = tmp_dir.path().clone().join("message.txt"); + let dec_path = tmp_dir.path().clone().join("message.txt.enc"); + + fs::write(&enc_path, message.as_bytes())?; + + let passphrase = "Test Passphrase"; + + // Generate key pair + let (public_key, secret_key) = KeyControKyber1024::keypair().expect("Failed to generate keypair"); + + // Instantiate Kyber for encryption with Kyber1024 + let mut encryptor = Kyber::::new(public_key.clone(), None)?; + + // Encrypt message + let (encrypt_message, cipher) = encryptor.encrypt_file(enc_path.clone(), passphrase.clone())?; + + let nonce = encryptor.get_nonce(); + + fs::remove_file(enc_path.clone()); + + // Instantiate Kyber for decryption with Kyber1024 + let mut decryptor = Kyber::::new(secret_key, Some(nonce?.to_string()))?; + + // Decrypt message + let decrypt_message = decryptor.decrypt_file(dec_path.clone(), passphrase.clone(), cipher)?; + + // Convert Vec to String for comparison + let decrypted_text = String::from_utf8(decrypt_message).expect("Failed to convert decrypted message to string"); + + // Assert that the decrypted message matches the original message + assert_eq!(decrypted_text, message.clone()); + + assert!(enc_path.exists(), "Decrypted file should exist after decryption."); + let decrypted_message = fs::read_to_string(&enc_path)?; + assert_eq!(decrypted_message, message, "Decrypted message should match the original message."); + + Ok(()) +} + +#[test] +fn encrypt_file_XChaCha20_Kyber768() -> Result<(), Box> { + let message = "Hey, how are you doing?"; + + let tmp_dir = TempDir::new().map_err(|e| CryptError::from(e))?; + let tmp_dir = Builder::new().prefix("messages").tempdir().map_err(|e| CryptError::from(e))?; + + let enc_path = tmp_dir.path().clone().join("message.txt"); + let dec_path = tmp_dir.path().clone().join("message.txt.enc"); + + fs::write(&enc_path, message.as_bytes())?; + + let passphrase = "Test Passphrase"; + + // Generate key pair + let (public_key, secret_key) = KeyControKyber768::keypair().expect("Failed to generate keypair"); + + // Instantiate Kyber for encryption with Kyber768 + let mut encryptor = Kyber::::new(public_key.clone(), None)?; + + // Encrypt message + let (encrypt_message, cipher) = encryptor.encrypt_file(enc_path.clone(), passphrase.clone())?; + + let nonce = encryptor.get_nonce(); + + fs::remove_file(enc_path.clone()); + + // Instantiate Kyber for decryption with Kyber768 + let mut decryptor = Kyber::::new(secret_key, Some(nonce?.to_string()))?; + + // Decrypt message + let decrypt_message = decryptor.decrypt_file(dec_path.clone(), passphrase.clone(), cipher)?; + + // Convert Vec to String for comparison + let decrypted_text = String::from_utf8(decrypt_message).expect("Failed to convert decrypted message to string"); + + // Assert that the decrypted message matches the original message + assert_eq!(decrypted_text, message.clone()); + + assert!(enc_path.exists(), "Decrypted file should exist after decryption."); + let decrypted_message = fs::read_to_string(&enc_path)?; + assert_eq!(decrypted_message, message, "Decrypted message should match the original message."); + + Ok(()) +} + +#[test] +fn encrypt_file_XChaCha20_Kyber512() -> Result<(), Box> { + let message = "Hey, how are you doing?"; + + let tmp_dir = TempDir::new().map_err(|e| CryptError::from(e))?; + let tmp_dir = Builder::new().prefix("messages").tempdir().map_err(|e| CryptError::from(e))?; + + let enc_path = tmp_dir.path().clone().join("message.txt"); + let dec_path = tmp_dir.path().clone().join("message.txt.enc"); + + fs::write(&enc_path, message.as_bytes())?; + + let passphrase = "Test Passphrase"; + + // Generate key pair + let (public_key, secret_key) = KeyControKyber512::keypair().expect("Failed to generate keypair"); + + // Instantiate Kyber for encryption with Kyber512 + let mut encryptor = Kyber::::new(public_key.clone(), None)?; + + // Encrypt message + let (encrypt_message, cipher) = encryptor.encrypt_file(enc_path.clone(), passphrase.clone())?; + + let nonce = encryptor.get_nonce(); + + fs::remove_file(enc_path.clone()); + + // Instantiate Kyber for decryption with Kyber512 + let mut decryptor = Kyber::::new(secret_key, Some(nonce?.to_string()))?; + + // Decrypt message + let decrypt_message = decryptor.decrypt_file(dec_path.clone(), passphrase.clone(), cipher)?; + + // Convert Vec to String for comparison + let decrypted_text = String::from_utf8(decrypt_message).expect("Failed to convert decrypted message to string"); + + // Assert that the decrypted message matches the original message + assert_eq!(decrypted_text, message.clone()); + + assert!(enc_path.exists(), "Decrypted file should exist after decryption."); + let decrypted_message = fs::read_to_string(&enc_path)?; + assert_eq!(decrypted_message, message, "Decrypted message should match the original message."); + + Ok(()) +} \ No newline at end of file diff --git a/src/tests/mod.rs b/src/tests/mod.rs new file mode 100644 index 0000000..de7415a --- /dev/null +++ b/src/tests/mod.rs @@ -0,0 +1,20 @@ +use crate::activate_log; + +#[cfg(test)] +#[test] +fn begin() { + activate_log("crypt_tests.log") +} + +#[cfg(test)] +mod KyberKeyTest; + +#[cfg(test)] +mod kyber_tests; + +#[cfg(test)] +mod SignatureTests; + +#[cfg(test)] +mod LoggingTests; +