From 57cf8e2df87aac64eb4f8c1642a500256613ba72 Mon Sep 17 00:00:00 2001 From: M <149858635+mm9942@users.noreply.github.com> Date: Tue, 2 Apr 2024 11:19:06 +0200 Subject: [PATCH] new version release of version 1.1.4 --- Cargo.toml | 5 +- LICENSE.txt | 21 + README.md | 241 +++++----- examples/encrypt_aes.rs | 36 ++ examples/encrypt_xchacha.rs | 46 ++ src/Core/cipher_aes.rs | 244 ++++++++++ src/Core/cipher_xchacha.rs | 217 +++++++++ src/Core/kyber/KeyKyber.rs | 269 +++++++++++ src/Core/kyber/kyber_crypto.rs | 254 +++++++++++ src/Core/kyber/mod.rs | 251 +++++++++++ src/Core/mod.rs | 65 +++ src/KeyControl/file.rs | 166 +++++++ src/KeyControl/key.rs | 177 ++++++++ src/KeyControl/mod.rs | 134 ++++++ src/cryptography/cryptographic.rs | 236 ++++++++++ src/cryptography/mod.rs | 79 ++++ src/cryptography/signature/mod.rs | 197 ++++++++ src/cryptography/signature/sign.rs | 140 ++++++ src/cryptography/signature/sign_dilithium.rs | 228 ++++++++++ src/cryptography/signature/sign_falcon.rs | 229 ++++++++++ src/error.rs | 151 +++++++ src/lib.rs | 41 ++ src/tests/KyberKeyTest.rs | 160 +++++++ src/tests/kyber_tests.rs | 450 +++++++++++++++++++ src/tests/mod.rs | 8 + src/tests/signature_tests.rs | 186 ++++++++ 26 files changed, 4095 insertions(+), 136 deletions(-) create mode 100644 LICENSE.txt create mode 100644 examples/encrypt_aes.rs create mode 100644 examples/encrypt_xchacha.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/mod.rs create mode 100644 src/cryptography/signature/mod.rs create mode 100644 src/cryptography/signature/sign.rs create mode 100644 src/cryptography/signature/sign_dilithium.rs create mode 100644 src/cryptography/signature/sign_falcon.rs create mode 100644 src/error.rs create mode 100644 src/lib.rs create mode 100644 src/tests/KyberKeyTest.rs create mode 100644 src/tests/kyber_tests.rs create mode 100644 src/tests/mod.rs create mode 100644 src/tests/signature_tests.rs diff --git a/Cargo.toml b/Cargo.toml index e99f619..1ffca60 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "crypt_guard" -version = "1.1.0" +version = "1.1.4" 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" @@ -22,6 +22,7 @@ chacha20 = "0.9.1" pqcrypto-dilithium = "0.5.0" pqcrypto-kyber = "0.8.1" tempfile = "3.10.1" +# notify-rust = "4.10.0" [features] -tokio = ["dep:tokio"] \ No newline at end of file +tokio = ["dep:tokio"] diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..309666d --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 M + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md index d69a4e7..bc4535d 100644 --- a/README.md +++ b/README.md @@ -6,11 +6,11 @@ [![GitHub Library][lib-badge]][lib-link] [![GitHub CLI][cli-badge]][cli-link] -[crates-badge]: https://img.shields.io/badge/crates.io-v1.1.1-blue.svg +[crates-badge]: https://img.shields.io/badge/crates.io-v1.1-blue.svg [crates-url]: https://crates.io/crates/crypt_guard [mit-badge]: https://img.shields.io/badge/license-MIT-green.svg [mit-url]: https://github.com/mm9942/CryptGuardLib/blob/main/LICENSE -[doc-badge]: https://img.shields.io/badge/docs-v1.1.1-yellow.svg +[doc-badge]: https://img.shields.io/badge/docs-v1.1-yellow.svg [doc-url]: https://docs.rs/crypt_guard/ [lib-badge]: https://img.shields.io/badge/github-lib-black.svg [lib-link]: https://github.com/mm9942/CryptGuardLib @@ -18,186 +18,159 @@ [cli-link]: https://github.com/mm9942/CryptGuard ## Introduction + CryptGuard is a comprehensive cryptographic library, offering robust encryption and decryption capabilities. It integrates traditional cryptography with post-quantum algorithms, ensuring resilience against quantum computing threats. Designed for developers, CryptGuard empowers applications to withstand future digital security challenges. Embrace CryptGuard as your trusted ally in safeguarding privacy in the digital realm. +## Key Features and Capabilities + +This library supports AES-256 and XChaCha20 encryption algorithms, providing a secure means to protect data. To cater to a variety of security requirements and operational contexts, CryptGuard integrates seamlessly with Kyber512, Kyber768, and Kyber1024 for encryption, ensuring compatibility with post-quantum cryptography standards. + +For developers who require digital signing capabilities, CryptGuard incorporates Falcon and Dilithium algorithms, offering robust options for creating and verifying digital signatures. This feature is particularly crucial for applications that necessitate authenticity and integrity of data, ensuring that digital communications remain secure and verifiable. + +An additional layer of security is provided through the appending of a HMAC (Hash-Based Message Authentication Code) to encrypted data. This critical feature enables the authentication of encrypted information, ensuring that any tampering with the data can be reliably detected. This HMAC attachment underscores CryptGuard's commitment to comprehensive data integrity and security, offering developers and end-users peace of mind regarding the authenticity and safety of their data. + ## Syntax Overhaul and Version Information ### Upcoming Changes -Our library is undergoing a syntax overhaul to enhance detail and clarity, addressing feedback for a more intuitive user experience. The current syntax focuses on providing a comprehensive understanding of the cryptographic processes, albeit with a higher complexity level. +Our library is undergoing a syntax overhaul to enhance detail and clarity, addressing feedback for a more intuitive user experience. The current syntax focuses on providing a comprehensive understanding of the cryptographic processes, albeit with a different complexity level. ### Current Release -The present version, **1.1.x**, emphasizes detailed cryptographic operations, catering to users who require a deep dive into cryptographic functionalities. This version is ideal for those who prefer an elaborate approach to cryptography and don't want to use async code, async capabilites will on a later updated reimplemented (but this time as a feature). For those who prefer an rather easy syntax, please use the last version: v1.0.3, until the next update is released. +The present version, **1.1.4**, emphasizes detailed cryptographic operations. This version is ideal for those who want a fast but not too complicated, elaborate approach to cryptography and don't want to use asynchronous code. Asynchronous capabilities will be reimplemented in a later update (but this time as a feature). For those who prefer an easier syntax, they should just use version 1.0.3 until a later update is released. This version's syntax is more user-friendly and does not require the definition of too many structs like in 1.1.1 or 1.1.0 but allows for precise control over the encryption and decryption algorithm as well as the Kyber key size. It allows the usage of Kyber1024, Kyber768, and Kyber512. ### Future Release -A forthcoming update will introduce a more streamlined and user-friendly interface that does not require such detailed usage of the included structs. This version aims to simplify cryptographic operations, making the library more accessible to a broader audience. It is also planned to contain support for other key sizes of Kyber besides Kyber1024. The structs are planned to be used from then on in the background, allowing the logging of information about an encryption — not the keys or data themselves, but the algorithms used in relation to the datetime at which it was used. This enables later review to confirm the algorithm and key size in the decryption of the data. Stay tuned for its release! +A forthcoming update will introduce other bit sizes for Falcon and Dilithium. It will also introduce logging capabilities, not logging keys or original data, but rather information about which encryption algorithm (AES or XChaCha20) was used, whether it was a File or a Message, as well as the time it was used. Stay tuned for its release! ## Important Considerations -### Data Handling in CryptographicInformation - -Users should note that providing an existing file path to `FileMetadata` for encryption/decryption operations will overwrite the `data` field within `CryptographicInformation` with the file's content. This ensures the use of current data but replaces any existing data in the field. Caution is advised to prevent data loss. - ### Transition to the New Version -For those considering the transition to the updated version upon its release, familiarizing yourself with the current documentation and examples is recommended. This preparation will facilitate a smoother adaptation to the new syntax and features. +For those considering the transition to the updated version upon its release, familiarizing yourself with the current documentation and examples is recommended. This preparation will facilitate a smoother adaptation to the new syntax and features. The next upcoming versions will gradually change the syntax and often implement things you don't need to use in the next version anymore, but these structs and methods don't cease to exist; rather, they are now automatically implemented for easier usage. If you want to use them, don't hesitate to do so! ## Usage Examples #### Generating and Saving a Key Pair -This example illustrates generating a key pair and saving it to files, leveraging the `KeyPair::new()` method for key pair generation and `FileMetadata::save()` for persisting keys. +This example illustrates generating a key pair and saving it to files, leveraging the `KeyControKyber1024::keypair()` method for key pair generation and the `KeyControl::` instance for setting and saving the keys. ```rust -use crate::KeyControl::{FileMetadata, KeyPair}; -use crate::KeyControl::FileTypes; - -let key_pair = KeyPair::new(); - -// Public key saving -let public_key_file_metadata = FileMetadata::from( - "path/to/save/public_key.pub".into(), - FileTypes::PublicKey, - FileState::Other, -); -public_key_file_metadata.save(key_pair.public_key.content().unwrap()).expect("Failed to save public key"); - -// Secret key saving -let secret_key_file_metadata = FileMetadata::from( - "path/to/save/secret_key.sec".into(), - FileTypes::SecretKey, - FileState::Other, -); -secret_key_file_metadata.save(key_pair.secret_key.content().unwrap()).expect("Failed to save secret key"); + // Generate a keypair + let (public_key, secret_key) = KeyControKyber1024::keypair().unwrap(); + + let keycontrol = KeyControl::::new(); + + // Save Public and Secret key while defining the folder (./key). + keycontrol.set_public_key(public_key.clone()).unwrap(); + keycontrol.save(KeyTypes::PublicKey, "./key".into()).unwrap(); + + keycontrol.set_secret_key(secret_key.clone()).unwrap(); + keycontrol.save(KeyTypes::SecretKey, "./key".into()).unwrap(); ``` -### Encrypting a Message using AES +### Encryption of a File using AES ```rust -let keyp = KeyPair::new(); - -let file1 = FileMetadata::from( - PathBuf::from("key.pub"), - FileTypes::PublicKey, - FileState::Other -); - -let file2 = FileMetadata::from( - PathBuf::from("key.sec"), - FileTypes::SecretKey, - FileState::Other -); - -let mut pubk = keyp.public_key().unwrap(); -let mut seck = keyp.secret_key().unwrap(); -let _ = file1.save(pubk.content().unwrap()); -let _ = file2.save(seck.content().unwrap()); - -let crypt_metadata1 = CryptographicMetadata::from( - Process::encryption(), - CryptographicMechanism::aes(), - KeyEncapMechanism::kyber1024(), - ContentType::message(), -); - -let crypt_info1 = CryptographicInformation::from( - "This is a test message".as_bytes().to_vec(), - "passphrase".as_bytes().to_vec(), - crypt_metadata1, - false, - None, -); -let mut aes1 = CipherAES::new(crypt_info1); - -let pubkey = Key::new(KeyTypes::PublicKey, keyp.public_key().unwrap().content().unwrap().to_vec()); -let seckey = Key::new(KeyTypes::SecretKey, keyp.secret_key().unwrap().content().unwrap().to_vec()); - -let (data, cipher) = aes1.encrypt(pubkey).unwrap(); + let message = "Hey, how are you doing?"; + let passphrase = "Test Passphrase"; + + // Instantiate Kyber for encryption of a message with Kyber1024 and AES + // Fails when not using either of these properties since it would be the wrong type of algorithm, data, keysize or process! + let mut encryptor = Kyber::::new(public_key.clone(), None)?; + + // Encrypt message + let (encrypt_message, cipher) = encryptor.encrypt_msg(message.clone(), passphrase.clone())?; + + // Save the ciphertext for decryption in folder ./key + key_control.set_ciphertext(cipher.clone()).unwrap(); + key_control.save(KeyTypes::Ciphertext, "./key".into()).unwrap(); +``` +### Decryption of a File using AES + +```rust + let cipher = key_control.load(KeyTypes::Ciphertext, Path::new("./key/ciphertext.ct")); + let secret_key = key_control.load(KeyTypes::SecretKey, Path::new("./key/secret_key.sec")); + + // Instantiate Kyber for decryption of a message with Kyber1024 and AES + // Fails when not using either of these properties since it would be the wrong type of algorithm, data, keysize or process! + let mut decryptor = Kyber::::new(secret_key, None)?; + + // Decrypt message + let decrypt_message = decryptor.decrypt_msg(encrypt_message.clone(), passphrase.clone(), cipher)?; + + // Print the decrypted text + println!("{:?}", String::from_utf8(decrypt_message)); ``` -#### Decrypting a File with XChaCha20 +#### Encryption and decryption of a message written into a file with XChaCha20 ```rust -let ciphertext = FileMetadata::from( - PathBuf::from("key.ct"), - FileTypes::Ciphertext, - FileState::Other -); - -let cipher_vec = ciphertext.load().unwrap(); -let cipher = Key::new(KeyTypes::Ciphertext, cipher_vec); - -let secret_key = FileMetadata::from( - PathBuf::from("key.sec"), - FileTypes::SecretKey, - FileState::Other -); - -let seckey_vec = secret_key.load().unwrap(); -let seckey = Key::new(KeyTypes::SecretKey, seckey_vec); - -let crypt_metadata2 = CryptographicMetadata::from( - Process::decryption(), - CryptographicMechanism::xchacha20(), - KeyEncapMechanism::kyber1024(), - ContentType::file(), -); - -let crypt_info2 = CryptographicInformation::from( - data, - "test key".as_bytes().to_vec(), - crypt_metadata2, - true, - location: Some( - FileMetadata::from( - PathBuf::from("./example.pdf.enc"), - FileTypes::File, - FileState::Decrypted - ) - ), -); - -let nonce_vec = ... // Use the nonce used for encryption - -let mut ChaCha1 = CipherChaCha::new(crypt_info1, Some(hex::encode(nonce_vec))); -let decrypted = ChaCha1.decrypt(seckey, cipher).unwrap(); + 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 of a file with Kyber768 and XChaCha20 + // Fails when not using either of these properties since it would be the wrong type of algorithm, data, keysize or process! + 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 of a file with Kyber768 and XChaCha20 + // Fails when not using either of these properties since it would be the wrong type of algorithm, data, keysize or process! + 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)?; ``` #### Signing and Verifying with Falcon ```rust -use crate::signature::{falcon, SignatureKey, SignatureMechanism, Mechanism}; + use crate::signature::{falcon, SignatureKey, SignatureMechanism, Mechanism}; -// Generate a keypair using Falcon -let falcon_keypair = falcon::keypair(); + // Generate a keypair using Falcon + let falcon_keypair = falcon::keypair(); -// Sign a message -let message = "This is a secret message"; -let signature = falcon::sign_msg(&falcon_keypair.secret_key, message.as_bytes()).expect("Signing failed"); + // Sign a message + let message = "This is a secret message"; + let signature = falcon::sign_msg(&falcon_keypair.secret_key, message.as_bytes()).expect("Signing failed"); -// Verify the signature -let verified = falcon::verify_msg(&falcon_keypair.public_key, &signature, message.as_bytes()).expect("Verification failed"); -assert!(verified, "Signature verification failed"); + // Verify the signature + let verified = falcon::verify_msg(&falcon_keypair.public_key, &signature, message.as_bytes()).expect("Verification failed");´ ``` #### Signing and Verifying with Dilithium ```rust -use crate::signature::{dilithium, SignatureKey, SignatureMechanism, Mechanism}; + use crate::signature::{dilithium, SignatureKey, SignatureMechanism, Mechanism}; -// Generate a keypair using Dilithium -let dilithium_keypair = dilithium::keypair(); + // Generate a keypair using Dilithium + let dilithium_keypair = dilithium::keypair(); -// Sign a message -let message = "Another secret message"; -let signature = dilithium::sign_msg(&dilithium_keypair.secret_key, message.as_bytes()).expect("Signing failed"); + // Sign a message + let message = "Another secret message"; + let signature = dilithium::sign_msg(&dilithium_keypair.secret_key, message.as_bytes()).expect("Signing failed"); -// Verify the signature -let verified = dilithium::verify_msg(&dilithium_keypair.public_key, &signature, message.as_bytes()).expect("Verification failed"); -assert!(verified, "Signature verification failed with Dilithium"); + // Verify the signature + let verified = dilithium::verify_msg(&dilithium_keypair.public_key, &signature, message.as_bytes()).expect("Verification failed");´ ``` @@ -208,4 +181,4 @@ We appreciate your engagement with our cryptographic library. As we strive to im Thank you for your support and for making security a priority in your projects. ## License -CryptGuard is licensed under the MIT LICENSE. The full license text is available in the `LICENSE` file in the repository. +CryptGuard is licensed under the MIT LICENSE. The full license text is available in the `LICENSE` file in the repository. \ No newline at end of file diff --git a/examples/encrypt_aes.rs b/examples/encrypt_aes.rs new file mode 100644 index 0000000..44d81e9 --- /dev/null +++ b/examples/encrypt_aes.rs @@ -0,0 +1,36 @@ +//use crypt_guard::KeyKyber::KeyControl; +use crypt_guard::{*, error::*}; +use std::{ + fs::{self, File}, + marker::PhantomData, + path::{PathBuf, Path}, + io::{Read, Write}, + +}; +use tempfile::{TempDir, Builder}; + +fn main() -> 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 of a message with Kyber1024 and AES + // Fails when not using either of these properties since it would be the wrong type of algorithm, data, keysize or process! + 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 of a message with Kyber1024 and AES + // Fails when not using either of these properties since it would be the wrong type of algorithm, data, keysize or process! + let mut decryptor = Kyber::::new(secret_key, None)?; + + // Decrypt message + let decrypt_message = decryptor.decrypt_msg(encrypt_message.clone(), passphrase.clone(), cipher)?; + + let decrypted_text = String::from_utf8(decrypt_message).expect("Failed to convert decrypted message to string"); + println!("{:?}", decrypted_text); + Ok(()) +} \ No newline at end of file diff --git a/examples/encrypt_xchacha.rs b/examples/encrypt_xchacha.rs new file mode 100644 index 0000000..66d72f5 --- /dev/null +++ b/examples/encrypt_xchacha.rs @@ -0,0 +1,46 @@ +use crypt_guard::{*, error::*}; +use std::{ + fs::{self, File}, + marker::PhantomData, + path::{PathBuf, Path}, + io::{Read, Write}, + +}; +use tempfile::{TempDir, Builder}; + + +fn main() -> 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 of a file with Kyber768 and XChaCha20 + // Fails when not using either of these properties since it would be the wrong type of algorithm, data, keysize or process! + 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 of a file with Kyber768 and XChaCha20 + // Fails when not using either of these properties since it would be the wrong type of algorithm, data, keysize or process! + 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)?; + Ok(()) +} \ 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..3c58845 --- /dev/null +++ b/src/Core/cipher_aes.rs @@ -0,0 +1,244 @@ +use crate::{ + *, + error::CryptError, + signature::*, + 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..fe537f0 --- /dev/null +++ b/src/Core/cipher_xchacha.rs @@ -0,0 +1,217 @@ +use crate::{ + *, + cryptography::*, + error::*, + signature::*, + 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; +use crate::signature::*; + + +/// 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..8712558 --- /dev/null +++ b/src/Core/kyber/KeyKyber.rs @@ -0,0 +1,269 @@ +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::*; + + let (pk, sk) = keypair(); + let public_key = pk.as_bytes().to_owned(); + let secret_key = sk.as_bytes().to_owned(); + + 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::*; + + 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(); + + 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::*; + + 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(); + + 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::*; + + let (pk, sk) = keypair(); + let public_key = pk.as_bytes().to_vec(); + let secret_key = sk.as_bytes().to_vec(); + + 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::*; + + 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(); + + 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::*; + + 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(); + + 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::*; + + let (pk, sk) = keypair(); + let public_key = pk.as_bytes().to_vec(); + let secret_key = sk.as_bytes().to_vec(); + + 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::*; + + 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(); + + 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::*; + + 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(); + + 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..130758d --- /dev/null +++ b/src/Core/kyber/kyber_crypto.rs @@ -0,0 +1,254 @@ +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() { + return Err(CryptError::FileNotFound); + } + + let key_encap_mechanism = match KyberSize::variant() { + KyberVariant::Kyber512 => KeyEncapMechanism::kyber512(), + KyberVariant::Kyber768 => KeyEncapMechanism::kyber768(), + KyberVariant::Kyber1024 => KeyEncapMechanism::kyber1024(), + }; + 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); + + let (data, cipher) = aes.encrypt(self.kyber_data.key()?).unwrap(); + + 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 = match KyberSize::variant() { + KyberVariant::Kyber512 => KeyEncapMechanism::kyber512(), + KyberVariant::Kyber768 => KeyEncapMechanism::kyber768(), + KyberVariant::Kyber1024 => KeyEncapMechanism::kyber1024(), + }; + 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); + + let (data, cipher) = aes.encrypt(self.kyber_data.key()?).unwrap(); + + 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() { + return Err(CryptError::FileNotFound); + } + + let key_encap_mechanism = match KyberSize::variant() { + KyberVariant::Kyber512 => KeyEncapMechanism::kyber512(), + KyberVariant::Kyber768 => KeyEncapMechanism::kyber768(), + KyberVariant::Kyber1024 => KeyEncapMechanism::kyber1024(), + }; + 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); + + let data = aes.decrypt(self.kyber_data.key()?, ciphertext).unwrap(); + 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 = match KyberSize::variant() { + KyberVariant::Kyber512 => KeyEncapMechanism::kyber512(), + KyberVariant::Kyber768 => KeyEncapMechanism::kyber768(), + KyberVariant::Kyber1024 => KeyEncapMechanism::kyber1024(), + }; + 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); + + let data = aes.decrypt(self.kyber_data.key()?, ciphertext).unwrap(); + 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() { + return Err(CryptError::FileNotFound); + } + + let key_encap_mechanism = match KyberSize::variant() { + KyberVariant::Kyber512 => KeyEncapMechanism::kyber512(), + KyberVariant::Kyber768 => KeyEncapMechanism::kyber768(), + KyberVariant::Kyber1024 => KeyEncapMechanism::kyber1024(), + }; + 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); + + let _ = self.kyber_data.set_nonce(hex::encode(xchacha.nonce())); + + let (data, cipher) = xchacha.encrypt(self.kyber_data.key()?).unwrap(); + 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 = match KyberSize::variant() { + KyberVariant::Kyber512 => KeyEncapMechanism::kyber512(), + KyberVariant::Kyber768 => KeyEncapMechanism::kyber768(), + KyberVariant::Kyber1024 => KeyEncapMechanism::kyber1024(), + }; + 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); + + let _ = self.kyber_data.set_nonce(hex::encode(xchacha.nonce())); + + let (data, cipher) = xchacha.encrypt(self.kyber_data.key()?).unwrap(); + + 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() { + return Err(CryptError::FileNotFound); + } + + let key_encap_mechanism = match KyberSize::variant() { + KyberVariant::Kyber512 => KeyEncapMechanism::kyber512(), + KyberVariant::Kyber768 => KeyEncapMechanism::kyber768(), + KyberVariant::Kyber1024 => KeyEncapMechanism::kyber1024(), + }; + 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())); + + let data = xchacha.decrypt(self.kyber_data.key()?, ciphertext).unwrap(); + 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 = match KyberSize::variant() { + KyberVariant::Kyber512 => KeyEncapMechanism::kyber512(), + KyberVariant::Kyber768 => KeyEncapMechanism::kyber768(), + KyberVariant::Kyber1024 => KeyEncapMechanism::kyber1024(), + }; + 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())); + + let data = xchacha.decrypt(self.kyber_data.key()?, ciphertext).unwrap(); + println!("data: {:?}", data); + Ok(data) + } +} diff --git a/src/Core/kyber/mod.rs b/src/Core/kyber/mod.rs new file mode 100644 index 0000000..5e59fcd --- /dev/null +++ b/src/Core/kyber/mod.rs @@ -0,0 +1,251 @@ +pub mod KeyKyber; +mod kyber_crypto; +pub use kyber_crypto::*; +use pqcrypto_traits::kem::{PublicKey, SecretKey, SharedSecret, Ciphertext}; +use crate::{ + *, + cryptography::*, + error::CryptError, + signature::*, + 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, + 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 }, + 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() + } +} + +/// Usable when KyberSize = Kyber1024 +impl Kyber { + pub fn kyber768(self) -> Result, CryptError> { + Ok(Kyber:: {kyber_data: self.kyber_data, 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, 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, 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, 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, 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, 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, + 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, + 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, + 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, + 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, + 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, + content_state: PhantomData, + kyber_state: PhantomData, + algorithm_state: PhantomData, + process_state: PhantomData, + } + } +} \ No newline at end of file diff --git a/src/Core/mod.rs b/src/Core/mod.rs new file mode 100644 index 0000000..8bfdb26 --- /dev/null +++ b/src/Core/mod.rs @@ -0,0 +1,65 @@ +use crate::{cryptography::*, error::CryptError, signature::*}; + +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/mod.rs b/src/cryptography/mod.rs new file mode 100644 index 0000000..0e0f267 --- /dev/null +++ b/src/cryptography/mod.rs @@ -0,0 +1,79 @@ + /// The `signature` module provides functionality for generating, managing, and verifying digital signatures, supporting various algorithms including post-quantum secure schemes. +pub mod signature; + +/// 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}; + +/// 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, +} + +/// 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, +} + +/// Enumerates the cryptographic mechanisms supported, such as AES and XChaCha20. +#[derive(PartialEq, Debug, Copy, Clone)] +pub enum CryptographicMechanism { + AES, + XChaCha20, +} + +/// Enumerates the key encapsulation mechanisms supported, such as Kyber1024. +#[derive(PartialEq, Debug, Copy, Clone)] +pub enum KeyEncapMechanism { + Kyber1024, + Kyber768, + Kyber512, +} + +/// 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, +} + +/// Enumerates the cryptographic processes, such as encryption and decryption. +#[derive(PartialEq, Debug, Copy, Clone)] +pub enum Process { + Encryption, + Decryption, +} + +/// 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, +} + +/// 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, +} \ No newline at end of file diff --git a/src/cryptography/signature/mod.rs b/src/cryptography/signature/mod.rs new file mode 100644 index 0000000..12cfa8e --- /dev/null +++ b/src/cryptography/signature/mod.rs @@ -0,0 +1,197 @@ +mod sign; +pub mod sign_falcon; +pub mod sign_dilithium; +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/signature/sign.rs b/src/cryptography/signature/sign.rs new file mode 100644 index 0000000..ac07bac --- /dev/null +++ b/src/cryptography/signature/sign.rs @@ -0,0 +1,140 @@ +use crate::signature::*; +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}, + SignType::Falcon => unimplemented!(), + SignType::Dilithium => unimplemented!(), + } + } + + /// 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() + }, + } + } + + /// 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 + }, + SignType::Falcon => unimplemented!(), + SignType::Dilithium => unimplemented!(), + } + } + + /// 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/signature/sign_dilithium.rs b/src/cryptography/signature/sign_dilithium.rs new file mode 100644 index 0000000..0637cb7 --- /dev/null +++ b/src/cryptography/signature/sign_dilithium.rs @@ -0,0 +1,228 @@ +//! # Dilithium Signature Module +//! +//! This module provides functionality for generating and verifying +//! Dilithium signatures. It includes support for key generation, signing +//! messages, and verifying signatures. This module is built upon the +//! `pqcrypto_dilithium` crate for post-quantum cryptographic operations. + +use crate::signature::*; +use pqcrypto_dilithium::dilithium5::{*, keypair}; // Adjusted for Dilithium specific functionality +use pqcrypto_dilithium::dilithium5; +use pqcrypto_traits::sign::{PublicKey, SecretKey, SignedMessage, DetachedSignature}; +use std::{ + fs::File, + io::Write, +}; + +/// Represents a Dilithium signature mechanism including the data, +/// signature, and secret key components necessary for signing and +/// verification processes. +#[derive(PartialEq, Debug, Clone)] +pub struct dilithium { + /// The data to be signed or verified. + pub data: Vec, + /// The mechanism used for the signature process. + pub signature: SignatureMechanism, + /// The secret key used for signing the data. + pub secret_key: SignatureKey, +} + +impl dilithium { + /// Constructs a new Dilithium signature element with specified data, public key, and secret key. + /// + /// This constructor adapts to various needs such as signing and key generation. It is crucial to use the parameters according to the specific requirements of the operation being performed. + /// + /// # Parameters + /// - `data`: Data intended for signing. This is optional and can be empty (`Vec::new()`) for key generation operations. For signing, it should be populated with the content to be signed. + /// - `public_key`: The public key used in the verification process. It is necessary for verifying signatures and does not play a role in the signing process itself. + /// - `secret_key`: The secret key used for signing data. This is essential for the creation of signatures and is not used in verification. + /// + /// # Usage + /// - To generate a new key pair, leave `data` empty. + /// - For signing operations, ensure `data` is populated with the content to be signed. + pub fn new(data: Vec, public_key: Vec, secret_key: Vec) -> Self { + let mut secret = SignatureKey::new(); + let _ = secret.set_secret_key(secret_key); + let signature = SignatureMechanism::new(public_key); + dilithium { data, signature, secret_key: secret } + } + + /// Sets the data to be signed. + /// + /// # Parameters + /// - `data`: The data to be used. + /// + /// # Returns + /// A result containing a reference to the data on success, or + /// a `SigningErr` on failure. + pub fn set_data(&mut self, data: Vec) -> Result<&[u8], SigningErr> { + self.data = data; + Ok(&self.data) + } + + /// Sets the secret key for signing operations. + /// + /// # Parameters + /// - `key`: The secret key in bytes. + /// + /// # Returns + /// A result containing a reference to the `SignatureKey` on success, + /// or a `SigningErr` on failure. + pub fn set_secret_key(&mut self, key: Vec) -> Result<&SignatureKey, SigningErr> { + let _ = self.secret_key.set_secret_key(key); + Ok(&self.secret_key) + } + + /// Sets the secret key for verification operations. + /// + /// # Parameters + /// - `key`: The secret key in bytes. + /// + /// # Returns + /// A result containing a reference to the `SignatureKey` on success, + /// or a `SigningErr` on failure. + pub fn set_public_key(&mut self, key: Vec) -> Result<&SignatureKey, SigningErr> { + let _ = self.signature.public_key.set_public_key(key); + Ok(&self.signature.public_key) + } + + /// Sets the signed message for verification operations. + /// + /// # Parameters + /// - `signature`: The secret key in bytes. + /// + /// # Returns + /// A result containing a reference to the `signature` as byte slice on success, + /// or a `SigningErr` on failure. + pub fn set_signed_msg(&mut self, signature: Vec) -> Result<&[u8], SigningErr> { + let _ = self.signature.set_signed_msg(signature)?; + Ok(self.signature.signature()?) + } + + /// Sets the detached signature for verification operations. + /// + /// # Parameters + /// - `signature`: The secret key in bytes. + /// + /// # Returns + /// A result containing a reference to the `signature` as byte slice on success, + /// or a `SigningErr` on failure. + pub fn set_detached(&mut self, signature: Vec) -> Result<&[u8], SigningErr> { + let _ = self.signature.set_detached_sign(signature)?; + Ok(self.signature.signature()?) + } +} + +impl Mechanism for dilithium { + /// Generates a new keypair for Dilithium signature operations. + /// + /// # Returns + /// A new `dilithium` instance with generated public and secret keys. + fn keypair() -> Self { + let (pk, sk) = keypair(); + let mut secret = SignatureKey::new(); + let _ = secret.set_secret_key(sk.as_bytes().to_vec()); + let signature = SignatureMechanism::new(pk.as_bytes().to_vec()); + dilithium { data: Vec::new(), signature, secret_key: secret } + } + + // Signs a message using the Dilithium signature scheme. + /// + /// # Returns + /// A result containing the signed message on success, or + /// a `SigningErr` on failure. + fn sign_msg(&mut self) -> Result, SigningErr> { + let sk = dilithium5::SecretKey::from_bytes(&self.secret_key.secret_key().unwrap())?; + let signed_message = dilithium5::sign(&self.data, &sk); + Ok(signed_message.as_bytes().to_vec()) + } + + /// Creates a detached signature for the data using the Dilithium signature scheme. + /// + /// # Returns + /// A result containing the detached signature as a `Vec` on success, + /// or a `SigningErr` on failure. + /// + /// This function generates a signature that can be verified independently of the original message. + fn sign_detached(&mut self) -> Result, SigningErr> { + let sk = dilithium5::SecretKey::from_bytes(&self.secret_key.secret_key().unwrap())?; + let signature = dilithium5::detached_sign(&self.data, &sk); + Ok(signature.as_bytes().to_vec()) + } + + + /// Saves a signed message to a specified file. + /// + /// # Parameters + /// - `path`: The path where the signed message will be saved. + /// + /// # Returns + /// A result indicating success or an error of type `SigningErr`. + /// + /// This function writes the signed message to a file, creating the file if it does not exist. + /// Errors may occur due to missing signature data or file system issues. + fn save_signed_msg(&self, path: PathBuf) -> Result<(), SigningErr> { + let signed_message = self.signature.signature().map_err(|_| SigningErr::SignatureMissing)?; + let mut file = File::create(path).map_err(|_| SigningErr::FileCreationFailed)?; + file.write_all(signed_message).map_err(|_| SigningErr::FileWriteFailed)?; + Ok(()) + } + + /// Saves a detached signature to a specified file. + /// + /// # Parameters + /// - `path`: The path where the detached signature will be saved. + /// + /// # Returns + /// A result indicating success or an error of type `SigningErr`. + /// + /// This function writes the detached signature to a file, creating the file if it does not exist. + /// Errors may occur due to missing signature data or file system issues. + fn save_detached(&self, path: PathBuf) -> Result<(), SigningErr> { + let signature = self.signature.signature().map_err(|_| SigningErr::SignatureMissing)?; + let mut file = File::create(path).map_err(|_| SigningErr::FileCreationFailed)?; + file.write_all(signature).map_err(|_| SigningErr::FileWriteFailed)?; + Ok(()) + } + + /// Verifies a signed message using the public key. + /// + /// # Returns + /// A result containing the original message if the verification succeeds, + /// or a `SigningErr` if verification fails. + /// + /// This function attempts to verify the authenticity and integrity of the signed message. + /// A verification failure occurs if the message has been tampered with or the wrong public key is used. + fn verify_msg(&mut self) -> Result, SigningErr> { + if self.signature.is_signed_msg()? { + let pk = dilithium5::PublicKey::from_bytes(&self.signature.public_key.public_key().unwrap())?; + let sm = dilithium5::SignedMessage::from_bytes(&self.signature.signature().unwrap())?; + let verified = pqcrypto_dilithium::dilithium5::open(&sm, &pk) + .map_err(|_| SigningErr::SignatureVerificationFailed)?; + Ok(verified) + } else { + Err(SigningErr::SignatureVerificationFailed) + } + } + + /// Verifies a detached signature against the original data using the public key. + /// + /// # Returns + /// A result indicating whether the verification is successful (`true`) or not (`false`), + /// or a `SigningErr` on failure. + /// + /// This function verifies the signature separately from the original message. + /// Useful for cases where the message is available but its integrity needs to be verified without modifying it. + fn verify_detached(&mut self) -> Result { + if !self.signature.is_signed_msg()? { + let pk = dilithium5::PublicKey::from_bytes(&self.signature.public_key.public_key().unwrap()) + .map_err(|_| SigningErr::PublicKeyMissing)?; + let ds = dilithium5::DetachedSignature::from_bytes(&self.signature.signature().unwrap())?; + dilithium5::verify_detached_signature(&ds, &self.data, &pk) + .map(|_| true) + .map_err(|_| SigningErr::SignatureVerificationFailed) + } else { + Err(SigningErr::SignatureVerificationFailed) + } + } +} \ No newline at end of file diff --git a/src/cryptography/signature/sign_falcon.rs b/src/cryptography/signature/sign_falcon.rs new file mode 100644 index 0000000..6a1add3 --- /dev/null +++ b/src/cryptography/signature/sign_falcon.rs @@ -0,0 +1,229 @@ +//! # Falcon Signature Module +//! +//! This module provides functionality for generating and verifying +//! Falcon signatures. It includes support for key generation, signing +//! messages, and verifying signatures. This module is built upon the +//! `pqcrypto_falcon` crate for post-quantum cryptographic operations. + +use crate::signature::*; +use pqcrypto_falcon::falcon1024::*; +use pqcrypto_traits::sign::{PublicKey, SecretKey, SignedMessage, DetachedSignature}; +use pqcrypto_falcon::falcon1024; +use std::{ + fs::File, + io::Write, +}; + +/// Represents a Falcon signature mechanism including the data, +/// signature, and secret key components necessary for signing and +/// verification processes. +#[derive(PartialEq, Debug, Clone)] +pub struct falcon { + /// The data to be signed or verified. + pub data: Vec, + /// The mechanism used for the signature process. + pub signature: SignatureMechanism, + /// The secret key used for signing the data. + pub secret_key: SignatureKey, +} + + +impl falcon { + /// Constructs a new Falcon signature element with specified data, public key, and secret key. + /// + /// This constructor adapts to various needs such as signing and key generation. It is crucial to use the parameters according to the specific requirements of the operation being performed. + /// + /// # Parameters + /// - `data`: Data intended for signing. This is optional and can be empty (`Vec::new()`) for key generation operations. For signing, it should be populated with the content to be signed. **This parameter should not be used for adding verification data, as it would not clearly distinguish between a detached signature or a signed message, potentially leading to ambiguity in verification scenarios.** + /// - `public_key`: The public key used in the verification process. It is necessary for verifying signatures and does not play a role in the signing process itself. + /// - `secret_key`: The secret key used for signing data. This is essential for the creation of signatures and is not used in verification. + /// + /// # Usage + /// - To generate a new key pair, leave `data` empty. + /// - For signing operations, ensure `data` is populated with the content to be signed. + /// - For verification, instead of using this constructor to input verification data, employ the `set_signed_msg` or `set_detached` methods post-instantiation. These methods are specifically designed for handling signature data, ensuring clarity in whether the signature is detached or a signed message. + pub fn new(data: Vec, public_key: Vec, secret_key: Vec) -> Self { + let mut secret = SignatureKey::new(); + let _ = secret.set_secret_key(secret_key); + let signature = SignatureMechanism::new(public_key); + falcon { data, signature, secret_key: secret } + } + + /// Sets the data to be signed. + /// + /// # Parameters + /// - `data`: The data to be used. + /// + /// # Returns + /// A result containing a reference to the data on success, or + /// a `SigningErr` on failure. + pub fn set_data(&mut self, data: Vec) -> Result<&[u8], SigningErr> { + self.data = data; + Ok(&self.data) + } + + /// Sets the secret key for signing operations. + /// + /// # Parameters + /// - `key`: The secret key in bytes. + /// + /// # Returns + /// A result containing a reference to the `SignatureKey` on success, + /// or a `SigningErr` on failure. + pub fn set_secret_key(&mut self, key: Vec) -> Result<&SignatureKey, SigningErr> { + let _ = self.secret_key.set_secret_key(key); + Ok(&self.secret_key) + } + + /// Sets the secret key for verification operations. + /// + /// # Parameters + /// - `key`: The secret key in bytes. + /// + /// # Returns + /// A result containing a reference to the `SignatureKey` on success, + /// or a `SigningErr` on failure. + pub fn set_public_key(&mut self, key: Vec) -> Result<&SignatureKey, SigningErr> { + let _ = self.signature.public_key.set_public_key(key); + Ok(&self.signature.public_key) + } + + /// Sets the signed message for verification operations. + /// + /// # Parameters + /// - `signature`: The secret key in bytes. + /// + /// # Returns + /// A result containing a reference to the `signature` as byte slice on success, + /// or a `SigningErr` on failure. + pub fn set_signed_msg(&mut self, signature: Vec) -> Result<&[u8], SigningErr> { + let _ = self.signature.set_signed_msg(signature)?; + Ok(self.signature.signature()?) + } + + /// Sets the detached signature for verification operations. + /// + /// # Parameters + /// - `signature`: The secret key in bytes. + /// + /// # Returns + /// A result containing a reference to the `signature` as byte slice on success, + /// or a `SigningErr` on failure. + pub fn set_detached(&mut self, signature: Vec) -> Result<&[u8], SigningErr> { + let _ = self.signature.set_detached_sign(signature)?; + Ok(self.signature.signature()?) + } +} + +impl Mechanism for falcon { + /// Generates a new keypair for Falcon signature operations. + /// + /// # Returns + /// A new `falcon` instance with generated public and secret keys. + fn keypair() -> Self { + let (pk, sk) = keypair(); + let mut secret = SignatureKey::new(); + let _ = secret.set_secret_key(sk.as_bytes().to_vec()); + let signature = SignatureMechanism::new(pk.as_bytes().to_vec()); + falcon { data: Vec::new(), signature, secret_key: secret } + } + + // Signs a message using the Falcon signature scheme. + /// + /// # Returns + /// A result containing the signed message on success, or + /// a `SigningErr` on failure. + fn sign_msg(&mut self) -> Result, SigningErr> { + let sk = falcon1024::SecretKey::from_bytes(&self.secret_key.secret_key().unwrap())?; + let signed_message = falcon1024::sign(&self.data, &sk); + Ok(signed_message.as_bytes().to_vec()) + } + + /// Creates a detached signature for the data using the Falcon signature scheme. + /// + /// # Returns + /// A result containing the detached signature as a `Vec` on success, + /// or a `SigningErr` on failure. + /// + /// This function generates a signature that can be verified independently of the original message. + fn sign_detached(&mut self) -> Result, SigningErr> { + let sk = falcon1024::SecretKey::from_bytes(&self.secret_key.secret_key().unwrap())?; + let signature = falcon1024::detached_sign(&self.data, &sk); + Ok(signature.as_bytes().to_vec()) + } + + /// Saves a signed message to a specified file. + /// + /// # Parameters + /// - `path`: The path where the signed message will be saved. + /// + /// # Returns + /// A result indicating success or an error of type `SigningErr`. + /// + /// This function writes the signed message to a file, creating the file if it does not exist. + /// Errors may occur due to missing signature data or file system issues. + fn save_signed_msg(&self, path: PathBuf) -> Result<(), SigningErr> { + let signed_message = self.signature.signature().map_err(|_| SigningErr::SignatureMissing)?; + let mut file = File::create(path).map_err(|_| SigningErr::FileCreationFailed)?; + file.write_all(signed_message).map_err(|_| SigningErr::FileWriteFailed)?; + Ok(()) + } + + /// Saves a detached signature to a specified file. + /// + /// # Parameters + /// - `path`: The path where the detached signature will be saved. + /// + /// # Returns + /// A result indicating success or an error of type `SigningErr`. + /// + /// This function writes the detached signature to a file, creating the file if it does not exist. + /// Errors may occur due to missing signature data or file system issues. + fn save_detached(&self, path: PathBuf) -> Result<(), SigningErr> { + let signature = self.signature.signature().map_err(|_| SigningErr::SignatureMissing)?; + let mut file = File::create(path).map_err(|_| SigningErr::FileCreationFailed)?; + file.write_all(signature).map_err(|_| SigningErr::FileWriteFailed)?; + Ok(()) + } + + /// Verifies a signed message using the public key. + /// + /// # Returns + /// A result containing the original message if the verification succeeds, + /// or a `SigningErr` if verification fails. + /// + /// This function attempts to verify the authenticity and integrity of the signed message. + /// A verification failure occurs if the message has been tampered with or the wrong public key is used. + fn verify_msg(&mut self) -> Result, SigningErr> { + if self.signature.is_signed_msg()? { + let pk = falcon1024::PublicKey::from_bytes(&self.signature.public_key.public_key().unwrap())?; + let sm = falcon1024::SignedMessage::from_bytes(&self.signature.signature().unwrap())?; + let verified = pqcrypto_falcon::falcon1024::open(&sm, &pk) + .map_err(|_| SigningErr::SignatureVerificationFailed)?; + Ok(verified) + } else { + Err(SigningErr::SignatureVerificationFailed) + } + } + + /// Verifies a detached signature against the original data using the public key. + /// + /// # Returns + /// A result indicating whether the verification is successful (`true`) or not (`false`), + /// or a `SigningErr` on failure. + /// + /// This function verifies the signature separately from the original message. + /// Useful for cases where the message is available but its integrity needs to be verified without modifying it. + fn verify_detached(&mut self) -> Result { + if !self.signature.is_signed_msg()? { + let pk = falcon1024::PublicKey::from_bytes(&self.signature.public_key.public_key().unwrap()) + .map_err(|_| SigningErr::PublicKeyMissing)?; + let ds = falcon1024::DetachedSignature::from_bytes(&self.signature.signature().unwrap())?; + falcon1024::verify_detached_signature(&ds, &self.data, &pk) + .map(|_| true) + .map_err(|_| SigningErr::SignatureVerificationFailed) + } else { + Err(SigningErr::SignatureVerificationFailed) + } + } +} \ No newline at end of file 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..1563dd3 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,41 @@ +mod Core; +/// Cryptographic related functionalitys, enums structs and modules +mod cryptography; +mod KeyControl; +pub mod error; +#[cfg(test)] +mod tests; + +pub use crate::{ + KeyControl::{ + *, + file::*, + }, + Core::{ + *, + kyber::{ + *, + KeyKyber::{self, *}, + }, + }, + cryptography::{ + *, + signature::{ + sign_falcon::*, + sign_dilithium::* + }, + } + +}; + +use KeyControl::*; +use cryptography::*; + + +use pqcrypto_falcon::falcon1024::{self, *}; +use pqcrypto_kyber::kyber1024::{self, *}; +use std::{ + error::Error, + fmt::{self, *}, + io, +}; \ No newline at end of file diff --git a/src/tests/KyberKeyTest.rs b/src/tests/KyberKeyTest.rs new file mode 100644 index 0000000..e3b322b --- /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::{ + signature::*, + 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/kyber_tests.rs b/src/tests/kyber_tests.rs new file mode 100644 index 0000000..770b569 --- /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::*, *}, + 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..386144b --- /dev/null +++ b/src/tests/mod.rs @@ -0,0 +1,8 @@ +#[cfg(test)] +mod KyberKeyTest; + +#[cfg(test)] +mod kyber_tests; + +#[cfg(test)] +mod signature_tests; \ No newline at end of file diff --git a/src/tests/signature_tests.rs b/src/tests/signature_tests.rs new file mode 100644 index 0000000..8fbe707 --- /dev/null +++ b/src/tests/signature_tests.rs @@ -0,0 +1,186 @@ +use super::*; +use crate::error::CryptError; +use std::{ + fs::{self, File}, + io::{Read, self}, + path::{PathBuf, Path}, +}; +use crate::{ + signature::*, + falcon, + dilithium, + KeyControKyber1024, + KeyControKyber512, + KeyControKyber768, + Core::KeyControl, + KyberKeyFunctions, + KeyTypes, + FileTypes, + FileMetadata, + FileState, +}; + +use tempfile::{TempDir, Builder, tempdir}; + +#[test] +fn test_sign_and_verify_message() { + let mut instance = falcon::keypair(); + let message = b"Test message".to_vec(); + instance.set_data(message.clone()).unwrap(); + let signature = instance.sign_msg().expect("Failed to sign message"); + instance.set_signed_msg(signature).expect("Failed to set signed message"); + let verified_message = instance.verify_msg().expect("Failed to verify message"); + assert_eq!(verified_message, message, "The verified message does not match the original message"); +} + +#[test] +fn test_sign_and_verify_detached_signature() { + let mut instance = falcon::keypair(); + let message = b"Test message for detached signature".to_vec(); + instance.set_data(message.clone()).unwrap(); + let detached_signature = instance.sign_detached().expect("Failed to sign with a detached signature"); + instance.set_detached(detached_signature).expect("Failed to set detached signature"); + let verification_result = instance.verify_detached().expect("Failed to verify detached signature"); + assert!(verification_result, "Detached signature verification failed"); +} + +#[test] +fn test_save_signed_msg() { + let temp_dir = tempdir().unwrap(); + let file_path = temp_dir.path().join("signed_message.sig"); + + let mut instance = falcon::keypair(); + let message = b"This is a test message.".to_vec(); + instance.set_data(message.clone()).unwrap(); + + // Sign the message + let signature = instance.sign_msg().expect("Failed to sign message"); + instance.set_signed_msg(signature.clone()).expect("Failed to set signed message"); + + // Save the signed message + assert!(instance.save_signed_msg(file_path.clone()).is_ok(), "Failed to save signed message"); + + // Read and verify the contents of the saved file + let mut saved_file = File::open(file_path).unwrap(); + let mut saved_signature = Vec::new(); + saved_file.read_to_end(&mut saved_signature).unwrap(); + assert_eq!(signature, saved_signature, "The saved signed message does not match the expected signature"); +} + +#[test] +fn test_save_detached() { + let temp_dir = tempdir().unwrap(); + let file_path = temp_dir.path().join("detached_signature.sig"); + + let mut instance = falcon::keypair(); + let message = b"This is a test message for detached signature.".to_vec(); + instance.set_data(message.clone()).unwrap(); + + // Sign with a detached signature + let detached_signature = instance.sign_detached().expect("Failed to sign with a detached signature"); + instance.set_detached(detached_signature.clone()).expect("Failed to set detached signature"); + + // Save the detached signature + assert!(instance.save_detached(file_path.clone()).is_ok(), "Failed to save detached signature"); + + // Read and verify the contents of the saved file + let mut saved_file = File::open(file_path).unwrap(); + let mut saved_detached_signature = Vec::new(); + saved_file.read_to_end(&mut saved_detached_signature).unwrap(); + assert_eq!(detached_signature, saved_detached_signature, "The saved detached signature does not match the expected signature"); +} + +#[test] +fn test_sign_and_verify_message_dilithium() { + let mut instance = dilithium::keypair(); + let message = b"Test message".to_vec(); + instance.set_data(message.clone()).unwrap(); + let signature = instance.sign_msg().expect("Failed to sign message"); + instance.set_signed_msg(signature).expect("Failed to set signed message"); + let verified_message = instance.verify_msg().expect("Failed to verify message"); + assert_eq!(verified_message, message, "The verified message does not match the original message"); +} + +#[test] +fn test_sign_and_verify_detached_signature_dilithium() { + let mut instance = dilithium::keypair(); + let message = b"Test message for detached signature".to_vec(); + instance.set_data(message.clone()).unwrap(); + let detached_signature = instance.sign_detached().expect("Failed to sign with a detached signature"); + instance.set_detached(detached_signature).expect("Failed to set detached signature"); + let verification_result = instance.verify_detached().expect("Failed to verify detached signature"); + assert!(verification_result, "Detached signature verification failed"); +} + +#[test] +fn test_save_signed_msg_dilithium() { + let temp_dir = tempdir().unwrap(); + let file_path = temp_dir.path().join("signed_message.sig"); + + let mut instance = dilithium::keypair(); + let message = b"This is a test message.".to_vec(); + instance.set_data(message.clone()).unwrap(); + + // Sign the message + let signature = instance.sign_msg().expect("Failed to sign message"); + instance.set_signed_msg(signature.clone()).expect("Failed to set signed message"); + + // Save the signed message + assert!(instance.save_signed_msg(file_path.clone()).is_ok(), "Failed to save signed message"); + + // Read and verify the contents of the saved file + let mut saved_file = File::open(file_path).unwrap(); + let mut saved_signature = Vec::new(); + saved_file.read_to_end(&mut saved_signature).unwrap(); + assert_eq!(signature, saved_signature, "The saved signed message does not match the expected signature"); +} + +#[test] +fn test_save_detached_dilithium() { + let temp_dir = tempdir().unwrap(); + let file_path = temp_dir.path().join("detached_signature.sig"); + + let mut instance = dilithium::keypair(); + let message = b"This is a test message for detached signature.".to_vec(); + instance.set_data(message.clone()).unwrap(); + + // Sign with a detached signature + let detached_signature = instance.sign_detached().expect("Failed to sign with a detached signature"); + instance.set_detached(detached_signature.clone()).expect("Failed to set detached signature"); + + // Save the detached signature + assert!(instance.save_detached(file_path.clone()).is_ok(), "Failed to save detached signature"); + + // Read and verify the contents of the saved file + let mut saved_file = File::open(file_path).unwrap(); + let mut saved_detached_signature = Vec::new(); + saved_file.read_to_end(&mut saved_detached_signature).unwrap(); + assert_eq!(detached_signature, saved_detached_signature, "The saved detached signature does not match the expected signature"); +} + + +#[test] +fn test_generate_and_verify_sha256_hmac() { + let data = b"Example data for SHA256".to_vec(); + let passphrase = b"secret key".to_vec(); + + let mut sign = Sign::new(data.clone(), passphrase.clone(), Operation::Sign, SignType::Sha256); + let concat_data = sign.hmac(); + let mut verify_sign = Sign::new(concat_data, passphrase, Operation::Verify, SignType::Sha256); + let verified_data = verify_sign.verify_hmac().expect("HMAC verification failed"); + + assert_eq!(verified_data, data, "Verified data does not match the original data for SHA256"); +} + +#[test] +fn test_generate_and_verify_sha512_hmac() { + let data = b"Example data for SHA512".to_vec(); + let passphrase = b"secret key".to_vec(); + + let mut sign = Sign::new(data.clone(), passphrase.clone(), Operation::Sign, SignType::Sha512); + let concat_data = sign.hmac(); + let mut verify_sign = Sign::new(concat_data, passphrase, Operation::Verify, SignType::Sha512); + let verified_data = verify_sign.verify_hmac().expect("HMAC verification failed"); + + assert_eq!(verified_data, data, "Verified data does not match the original data for SHA512"); +} \ No newline at end of file