crypt_guard 2.0.5

CryptGuard is a post-quantum cryptography framework with NIST FIPS 203/204/205 (ML-KEM, ML-DSA, SLH-DSA) plus legacy Kyber/Falcon/Dilithium, combined with AES and XChaCha20.
Documentation
use crate::{cryptography::*, key_control::*};
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 AES as the cryptographic mechanism.
    pub fn aes_gcm_siv() -> Self {
        Self::AesGcmSiv
    }

    /// Specifies AES as the cryptographic mechanism.
    pub fn aes_ctr() -> Self {
        Self::AesCtr
    }

    /// Specifies XChaCha20 as the cryptographic mechanism.
    pub fn aes_xts() -> Self {
        Self::AesXts
    }

    /// Specifies XChaCha20 as the cryptographic mechanism.
    pub fn xchacha20() -> Self {
        Self::XChaCha20
    }
}

impl Default for CryptographicMechanism {
    fn default() -> Self {
        Self::new()
    }
}

/// 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
    }
}

impl Default for KeyEncapMechanism {
    fn default() -> Self {
        Self::new()
    }
}

/// 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
    }
    /// Specifies the content as a RawData.
    pub fn raw_data() -> Self {
        Self::RawData
    }
}

impl Default for ContentType {
    fn default() -> Self {
        Self::new()
    }
}

/// 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<Process, CryptError> {
        Ok(self.process)
    }

    /// Accessor method for encryption_type property
    pub fn encryption_type(self) -> Result<CryptographicMechanism, CryptError> {
        Ok(self.encryption_type)
    }

    /// Accessor method for key_type property
    pub fn key_type(self) -> Result<KeyEncapMechanism, CryptError> {
        Ok(self.key_type)
    }

    /// Accessor method for content_type property
    pub fn content_type(self) -> Result<ContentType, CryptError> {
        Ok(self.content_type)
    }
}

impl Default for CryptographicMetadata {
    fn default() -> Self {
        Self::new()
    }
}

impl Default for CryptographicInformation {
    fn default() -> Self {
        Self::new()
    }
}

/// 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<bool, CryptError> {
        Ok(self.location.is_some())
    }

    /// Sets the content to be encrypted or decrypted.
    pub fn set_data(&mut self, data: &[u8]) -> Result<(), CryptError> {
        let 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: &std::path::Path,
    ) -> Result<PathBuf, CryptError> {
        let mut new_file_path = file_path.to_path_buf();

        // 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<bool, CryptError> {
        Ok(self.safe)
    }

    /// Returns the file location.
    pub fn location(&self) -> Result<PathBuf, CryptError> {
        match &self.location {
            Some(path) => Ok(path.location()?),
            _ => Err(CryptError::PathError),
        }
    }

    /// Constructs a new instance with specified values.
    pub fn from(
        content: Vec<u8>,
        passphrase: Vec<u8>,
        metadata: CryptographicMetadata,
        safe: bool,
        location: Option<FileMetadata>,
    ) -> 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)
    }
}