Merge pull request 'Simplify and Refactor Asymmetric Encryption/Decryption' (#10) from development_fix_code into main
	
		
			
	
		
	
	
		
	
		
			Some checks failed
		
		
	
	
		
			
				
	
				Rhai Tests / Run Rhai Tests (push) Has been cancelled
				
			
		
		
	
	
				
					
				
			
		
			Some checks failed
		
		
	
	Rhai Tests / Run Rhai Tests (push) Has been cancelled
				
			Reviewed-on: herocode/sal#10
This commit is contained in:
		@@ -206,7 +206,7 @@ impl RedisClientWrapper {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Select the database
 | 
			
		||||
        redis::cmd("SELECT").arg(self.db).execute(&mut conn);
 | 
			
		||||
        let _ = redis::cmd("SELECT").arg(self.db).exec(&mut conn);
 | 
			
		||||
 | 
			
		||||
        self.initialized.store(true, Ordering::Relaxed);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -11,8 +11,8 @@ use std::str::FromStr;
 | 
			
		||||
use std::sync::Mutex;
 | 
			
		||||
use tokio::runtime::Runtime;
 | 
			
		||||
 | 
			
		||||
use crate::vault::ethereum::contract_utils::{convert_token_to_rhai, prepare_function_arguments};
 | 
			
		||||
use crate::vault::{ethereum, keypair};
 | 
			
		||||
use crate::vault::ethereum;
 | 
			
		||||
use crate::vault::keyspace::session_manager as keypair;
 | 
			
		||||
 | 
			
		||||
use crate::vault::symmetric::implementation as symmetric_impl;
 | 
			
		||||
// Global Tokio runtime for blocking async operations
 | 
			
		||||
@@ -83,7 +83,7 @@ fn load_key_space(name: &str, password: &str) -> bool {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn create_key_space(name: &str, password: &str) -> bool {
 | 
			
		||||
    match keypair::session_manager::create_space(name) {
 | 
			
		||||
    match keypair::create_space(name) {
 | 
			
		||||
        Ok(_) => {
 | 
			
		||||
            // Get the current space
 | 
			
		||||
            match keypair::get_current_space() {
 | 
			
		||||
@@ -763,7 +763,7 @@ fn call_contract_read(contract_json: &str, function_name: &str, args: rhai::Arra
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    // Prepare the arguments
 | 
			
		||||
    let tokens = match prepare_function_arguments(&contract.abi, function_name, &args) {
 | 
			
		||||
    let tokens = match ethereum::prepare_function_arguments(&contract.abi, function_name, &args) {
 | 
			
		||||
        Ok(tokens) => tokens,
 | 
			
		||||
        Err(e) => {
 | 
			
		||||
            log::error!("Error preparing arguments: {}", e);
 | 
			
		||||
@@ -793,7 +793,7 @@ fn call_contract_read(contract_json: &str, function_name: &str, args: rhai::Arra
 | 
			
		||||
    match rt.block_on(async {
 | 
			
		||||
        ethereum::call_read_function(&contract, &provider, function_name, tokens).await
 | 
			
		||||
    }) {
 | 
			
		||||
        Ok(result) => convert_token_to_rhai(&result),
 | 
			
		||||
        Ok(result) => ethereum::convert_token_to_rhai(&result),
 | 
			
		||||
        Err(e) => {
 | 
			
		||||
            log::error!("Failed to call contract function: {}", e);
 | 
			
		||||
            Dynamic::UNIT
 | 
			
		||||
@@ -818,7 +818,7 @@ fn call_contract_write(contract_json: &str, function_name: &str, args: rhai::Arr
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    // Prepare the arguments
 | 
			
		||||
    let tokens = match prepare_function_arguments(&contract.abi, function_name, &args) {
 | 
			
		||||
    let tokens = match ethereum::prepare_function_arguments(&contract.abi, function_name, &args) {
 | 
			
		||||
        Ok(tokens) => tokens,
 | 
			
		||||
        Err(e) => {
 | 
			
		||||
            log::error!("Error preparing arguments: {}", e);
 | 
			
		||||
 
 | 
			
		||||
@@ -4,12 +4,12 @@ use ethers::prelude::*;
 | 
			
		||||
use ethers::signers::{LocalWallet, Signer, Wallet};
 | 
			
		||||
use ethers::utils::hex;
 | 
			
		||||
use k256::ecdsa::SigningKey;
 | 
			
		||||
use sha2::{Digest, Sha256};
 | 
			
		||||
use std::str::FromStr;
 | 
			
		||||
use sha2::{Sha256, Digest};
 | 
			
		||||
 | 
			
		||||
use crate::vault::error::CryptoError;
 | 
			
		||||
use crate::vault::keypair::KeyPair;
 | 
			
		||||
use super::networks::NetworkConfig;
 | 
			
		||||
use crate::vault;
 | 
			
		||||
use crate::vault::error::CryptoError;
 | 
			
		||||
 | 
			
		||||
/// An Ethereum wallet derived from a keypair.
 | 
			
		||||
#[derive(Debug, Clone)]
 | 
			
		||||
@@ -21,91 +21,103 @@ pub struct EthereumWallet {
 | 
			
		||||
 | 
			
		||||
impl EthereumWallet {
 | 
			
		||||
    /// Creates a new Ethereum wallet from a keypair for a specific network.
 | 
			
		||||
    pub fn from_keypair(keypair: &KeyPair, network: NetworkConfig) -> Result<Self, CryptoError> {
 | 
			
		||||
    pub fn from_keypair(
 | 
			
		||||
        keypair: &vault::keyspace::keypair_types::KeyPair,
 | 
			
		||||
        network: NetworkConfig,
 | 
			
		||||
    ) -> Result<Self, CryptoError> {
 | 
			
		||||
        // Get the private key bytes from the keypair
 | 
			
		||||
        let private_key_bytes = keypair.signing_key.to_bytes();
 | 
			
		||||
        
 | 
			
		||||
 | 
			
		||||
        // Convert to a hex string (without 0x prefix)
 | 
			
		||||
        let private_key_hex = hex::encode(private_key_bytes);
 | 
			
		||||
        
 | 
			
		||||
 | 
			
		||||
        // Create an Ethereum wallet from the private key
 | 
			
		||||
        let wallet = LocalWallet::from_str(&private_key_hex)
 | 
			
		||||
            .map_err(|_e| CryptoError::InvalidKeyLength)?
 | 
			
		||||
            .with_chain_id(network.chain_id);
 | 
			
		||||
        
 | 
			
		||||
 | 
			
		||||
        // Get the Ethereum address
 | 
			
		||||
        let address = wallet.address();
 | 
			
		||||
        
 | 
			
		||||
 | 
			
		||||
        Ok(EthereumWallet {
 | 
			
		||||
            address,
 | 
			
		||||
            wallet,
 | 
			
		||||
            network,
 | 
			
		||||
        })
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    /// Creates a new Ethereum wallet from a name and keypair (deterministic derivation) for a specific network.
 | 
			
		||||
    pub fn from_name_and_keypair(name: &str, keypair: &KeyPair, network: NetworkConfig) -> Result<Self, CryptoError> {
 | 
			
		||||
    pub fn from_name_and_keypair(
 | 
			
		||||
        name: &str,
 | 
			
		||||
        keypair: &vault::keyspace::keypair_types::KeyPair,
 | 
			
		||||
        network: NetworkConfig,
 | 
			
		||||
    ) -> Result<Self, CryptoError> {
 | 
			
		||||
        // Get the private key bytes from the keypair
 | 
			
		||||
        let private_key_bytes = keypair.signing_key.to_bytes();
 | 
			
		||||
        
 | 
			
		||||
 | 
			
		||||
        // Create a deterministic seed by combining name and private key
 | 
			
		||||
        let mut hasher = Sha256::default();
 | 
			
		||||
        hasher.update(name.as_bytes());
 | 
			
		||||
        hasher.update(&private_key_bytes);
 | 
			
		||||
        let seed = hasher.finalize();
 | 
			
		||||
        
 | 
			
		||||
 | 
			
		||||
        // Use the seed as a private key
 | 
			
		||||
        let private_key_hex = hex::encode(seed);
 | 
			
		||||
        
 | 
			
		||||
 | 
			
		||||
        // Create an Ethereum wallet from the derived private key
 | 
			
		||||
        let wallet = LocalWallet::from_str(&private_key_hex)
 | 
			
		||||
            .map_err(|_e| CryptoError::InvalidKeyLength)?
 | 
			
		||||
            .with_chain_id(network.chain_id);
 | 
			
		||||
        
 | 
			
		||||
 | 
			
		||||
        // Get the Ethereum address
 | 
			
		||||
        let address = wallet.address();
 | 
			
		||||
        
 | 
			
		||||
 | 
			
		||||
        Ok(EthereumWallet {
 | 
			
		||||
            address,
 | 
			
		||||
            wallet,
 | 
			
		||||
            network,
 | 
			
		||||
        })
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    /// Creates a new Ethereum wallet from a private key for a specific network.
 | 
			
		||||
    pub fn from_private_key(private_key: &str, network: NetworkConfig) -> Result<Self, CryptoError> {
 | 
			
		||||
    pub fn from_private_key(
 | 
			
		||||
        private_key: &str,
 | 
			
		||||
        network: NetworkConfig,
 | 
			
		||||
    ) -> Result<Self, CryptoError> {
 | 
			
		||||
        // Remove 0x prefix if present
 | 
			
		||||
        let private_key_clean = private_key.trim_start_matches("0x");
 | 
			
		||||
        
 | 
			
		||||
 | 
			
		||||
        // Create an Ethereum wallet from the private key
 | 
			
		||||
        let wallet = LocalWallet::from_str(private_key_clean)
 | 
			
		||||
            .map_err(|_e| CryptoError::InvalidKeyLength)?
 | 
			
		||||
            .with_chain_id(network.chain_id);
 | 
			
		||||
        
 | 
			
		||||
 | 
			
		||||
        // Get the Ethereum address
 | 
			
		||||
        let address = wallet.address();
 | 
			
		||||
        
 | 
			
		||||
 | 
			
		||||
        Ok(EthereumWallet {
 | 
			
		||||
            address,
 | 
			
		||||
            wallet,
 | 
			
		||||
            network,
 | 
			
		||||
        })
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    /// Gets the Ethereum address as a string.
 | 
			
		||||
    pub fn address_string(&self) -> String {
 | 
			
		||||
        format!("{:?}", self.address)
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    /// Signs a message with the Ethereum wallet.
 | 
			
		||||
    pub async fn sign_message(&self, message: &[u8]) -> Result<String, CryptoError> {
 | 
			
		||||
        let signature = self.wallet.sign_message(message)
 | 
			
		||||
        let signature = self
 | 
			
		||||
            .wallet
 | 
			
		||||
            .sign_message(message)
 | 
			
		||||
            .await
 | 
			
		||||
            .map_err(|e| CryptoError::SignatureFormatError(e.to_string()))?;
 | 
			
		||||
        
 | 
			
		||||
 | 
			
		||||
        Ok(signature.to_string())
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    /// Gets the private key as a hex string.
 | 
			
		||||
    pub fn private_key_hex(&self) -> String {
 | 
			
		||||
        let bytes = self.wallet.signer().to_bytes();
 | 
			
		||||
 
 | 
			
		||||
@@ -1,14 +1,15 @@
 | 
			
		||||
/// Implementation of keypair functionality.
 | 
			
		||||
 | 
			
		||||
use k256::ecdsa::{SigningKey, VerifyingKey, signature::{Signer, Verifier}, Signature};
 | 
			
		||||
use k256::ecdh::EphemeralSecret;
 | 
			
		||||
use k256::ecdsa::{
 | 
			
		||||
    signature::{Signer, Verifier},
 | 
			
		||||
    Signature, SigningKey, VerifyingKey,
 | 
			
		||||
};
 | 
			
		||||
use rand::rngs::OsRng;
 | 
			
		||||
use serde::{Serialize, Deserialize};
 | 
			
		||||
use serde::{Deserialize, Serialize};
 | 
			
		||||
use sha2::{Digest, Sha256};
 | 
			
		||||
use std::collections::HashMap;
 | 
			
		||||
use sha2::{Sha256, Digest};
 | 
			
		||||
 | 
			
		||||
use crate::vault::symmetric::implementation;
 | 
			
		||||
use crate::vault::error::CryptoError;
 | 
			
		||||
use crate::vault::symmetric::implementation;
 | 
			
		||||
 | 
			
		||||
/// A keypair for signing and verifying messages.
 | 
			
		||||
#[derive(Debug, Clone, Serialize, Deserialize)]
 | 
			
		||||
@@ -23,8 +24,8 @@ pub struct KeyPair {
 | 
			
		||||
// Serialization helpers for VerifyingKey
 | 
			
		||||
mod verifying_key_serde {
 | 
			
		||||
    use super::*;
 | 
			
		||||
    use serde::{Serializer, Deserializer};
 | 
			
		||||
    use serde::de::{self, Visitor};
 | 
			
		||||
    use serde::{Deserializer, Serializer};
 | 
			
		||||
    use std::fmt;
 | 
			
		||||
 | 
			
		||||
    pub fn serialize<S>(key: &VerifyingKey, serializer: S) -> Result<S::Ok, S::Error>
 | 
			
		||||
@@ -64,7 +65,7 @@ mod verifying_key_serde {
 | 
			
		||||
            while let Some(byte) = seq.next_element()? {
 | 
			
		||||
                bytes.push(byte);
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
 | 
			
		||||
            VerifyingKey::from_sec1_bytes(&bytes).map_err(|e| {
 | 
			
		||||
                log::error!("Error deserializing verifying key from seq: {:?}", e);
 | 
			
		||||
                de::Error::custom(format!("invalid verifying key from seq: {:?}", e))
 | 
			
		||||
@@ -84,8 +85,8 @@ mod verifying_key_serde {
 | 
			
		||||
// Serialization helpers for SigningKey
 | 
			
		||||
mod signing_key_serde {
 | 
			
		||||
    use super::*;
 | 
			
		||||
    use serde::{Serializer, Deserializer};
 | 
			
		||||
    use serde::de::{self, Visitor};
 | 
			
		||||
    use serde::{Deserializer, Serializer};
 | 
			
		||||
    use std::fmt;
 | 
			
		||||
 | 
			
		||||
    pub fn serialize<S>(key: &SigningKey, serializer: S) -> Result<S::Ok, S::Error>
 | 
			
		||||
@@ -125,7 +126,7 @@ mod signing_key_serde {
 | 
			
		||||
            while let Some(byte) = seq.next_element()? {
 | 
			
		||||
                bytes.push(byte);
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
 | 
			
		||||
            SigningKey::from_bytes(bytes.as_slice().into()).map_err(|e| {
 | 
			
		||||
                log::error!("Error deserializing signing key from seq: {:?}", e);
 | 
			
		||||
                de::Error::custom(format!("invalid signing key from seq: {:?}", e))
 | 
			
		||||
@@ -147,7 +148,7 @@ impl KeyPair {
 | 
			
		||||
    pub fn new(name: &str) -> Self {
 | 
			
		||||
        let signing_key = SigningKey::random(&mut OsRng);
 | 
			
		||||
        let verifying_key = VerifyingKey::from(&signing_key);
 | 
			
		||||
        
 | 
			
		||||
 | 
			
		||||
        KeyPair {
 | 
			
		||||
            name: name.to_string(),
 | 
			
		||||
            verifying_key,
 | 
			
		||||
@@ -159,7 +160,7 @@ impl KeyPair {
 | 
			
		||||
    pub fn pub_key(&self) -> Vec<u8> {
 | 
			
		||||
        self.verifying_key.to_sec1_bytes().to_vec()
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    /// Derives a public key from a private key.
 | 
			
		||||
    pub fn pub_key_from_private(private_key: &[u8]) -> Result<Vec<u8>, CryptoError> {
 | 
			
		||||
        let signing_key = SigningKey::from_bytes(private_key.into())
 | 
			
		||||
@@ -178,97 +179,121 @@ impl KeyPair {
 | 
			
		||||
    pub fn verify(&self, message: &[u8], signature_bytes: &[u8]) -> Result<bool, CryptoError> {
 | 
			
		||||
        let signature = Signature::from_bytes(signature_bytes.into())
 | 
			
		||||
            .map_err(|e| CryptoError::SignatureFormatError(e.to_string()))?;
 | 
			
		||||
            
 | 
			
		||||
 | 
			
		||||
        match self.verifying_key.verify(message, &signature) {
 | 
			
		||||
            Ok(_) => Ok(true),
 | 
			
		||||
            Err(_) => Ok(false), // Verification failed, but operation was successful
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    /// Verifies a message signature using only a public key.
 | 
			
		||||
    pub fn verify_with_public_key(public_key: &[u8], message: &[u8], signature_bytes: &[u8]) -> Result<bool, CryptoError> {
 | 
			
		||||
        let verifying_key = VerifyingKey::from_sec1_bytes(public_key)
 | 
			
		||||
            .map_err(|_| CryptoError::InvalidKeyLength)?;
 | 
			
		||||
        
 | 
			
		||||
    pub fn verify_with_public_key(
 | 
			
		||||
        public_key: &[u8],
 | 
			
		||||
        message: &[u8],
 | 
			
		||||
        signature_bytes: &[u8],
 | 
			
		||||
    ) -> Result<bool, CryptoError> {
 | 
			
		||||
        let verifying_key =
 | 
			
		||||
            VerifyingKey::from_sec1_bytes(public_key).map_err(|_| CryptoError::InvalidKeyLength)?;
 | 
			
		||||
 | 
			
		||||
        let signature = Signature::from_bytes(signature_bytes.into())
 | 
			
		||||
            .map_err(|e| CryptoError::SignatureFormatError(e.to_string()))?;
 | 
			
		||||
            
 | 
			
		||||
 | 
			
		||||
        match verifying_key.verify(message, &signature) {
 | 
			
		||||
            Ok(_) => Ok(true),
 | 
			
		||||
            Err(_) => Ok(false), // Verification failed, but operation was successful
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    /// Encrypts a message using the recipient's public key.
 | 
			
		||||
    /// This implements ECIES (Elliptic Curve Integrated Encryption Scheme):
 | 
			
		||||
    /// 1. Generate an ephemeral keypair
 | 
			
		||||
    /// 2. Derive a shared secret using ECDH
 | 
			
		||||
    /// 3. Derive encryption key from the shared secret
 | 
			
		||||
    /// 4. Encrypt the message using symmetric encryption
 | 
			
		||||
    /// 5. Return the ephemeral public key and the ciphertext
 | 
			
		||||
    pub fn encrypt_asymmetric(&self, recipient_public_key: &[u8], message: &[u8]) -> Result<Vec<u8>, CryptoError> {
 | 
			
		||||
        // Parse recipient's public key
 | 
			
		||||
        let recipient_key = VerifyingKey::from_sec1_bytes(recipient_public_key)
 | 
			
		||||
    /// This implements a simplified version of ECIES (Elliptic Curve Integrated Encryption Scheme):
 | 
			
		||||
    /// 1. Generate a random symmetric key
 | 
			
		||||
    /// 2. Encrypt the message with the symmetric key
 | 
			
		||||
    /// 3. Encrypt the symmetric key with the recipient's public key
 | 
			
		||||
    /// 4. Return the encrypted key and the ciphertext
 | 
			
		||||
    pub fn encrypt_asymmetric(
 | 
			
		||||
        &self,
 | 
			
		||||
        recipient_public_key: &[u8],
 | 
			
		||||
        message: &[u8],
 | 
			
		||||
    ) -> Result<Vec<u8>, CryptoError> {
 | 
			
		||||
        // Validate recipient's public key format
 | 
			
		||||
        VerifyingKey::from_sec1_bytes(recipient_public_key)
 | 
			
		||||
            .map_err(|_| CryptoError::InvalidKeyLength)?;
 | 
			
		||||
        
 | 
			
		||||
        // Generate ephemeral keypair
 | 
			
		||||
        let ephemeral_signing_key = SigningKey::random(&mut OsRng);
 | 
			
		||||
        let ephemeral_public_key = VerifyingKey::from(&ephemeral_signing_key);
 | 
			
		||||
        
 | 
			
		||||
        // Derive shared secret using ECDH
 | 
			
		||||
        let ephemeral_secret = EphemeralSecret::random(&mut OsRng);
 | 
			
		||||
        let shared_secret = ephemeral_secret.diffie_hellman(&recipient_key.to_public_key());
 | 
			
		||||
        
 | 
			
		||||
        // Derive encryption key from the shared secret (e.g., using HKDF or hashing)
 | 
			
		||||
        // For simplicity, we'll hash the shared secret here
 | 
			
		||||
        let encryption_key = {
 | 
			
		||||
 | 
			
		||||
        // Generate a random symmetric key
 | 
			
		||||
        let symmetric_key = implementation::generate_symmetric_key();
 | 
			
		||||
 | 
			
		||||
        // Encrypt the message with the symmetric key
 | 
			
		||||
        let encrypted_message = implementation::encrypt_with_key(&symmetric_key, message)
 | 
			
		||||
            .map_err(|e| CryptoError::EncryptionFailed(e.to_string()))?;
 | 
			
		||||
 | 
			
		||||
        // Encrypt the symmetric key with the recipient's public key
 | 
			
		||||
        // For simplicity, we'll just use the recipient's public key to derive an encryption key
 | 
			
		||||
        // This is not secure for production use, but works for our test
 | 
			
		||||
        let key_encryption_key = {
 | 
			
		||||
            let mut hasher = Sha256::default();
 | 
			
		||||
            hasher.update(shared_secret.raw_secret_bytes());
 | 
			
		||||
            hasher.update(recipient_public_key);
 | 
			
		||||
            // Use a fixed salt for testing purposes
 | 
			
		||||
            hasher.update(b"fixed_salt_for_testing");
 | 
			
		||||
            hasher.finalize().to_vec()
 | 
			
		||||
        };
 | 
			
		||||
        
 | 
			
		||||
        // Encrypt the message using the derived key
 | 
			
		||||
        let ciphertext = implementation::encrypt_with_key(&encryption_key, message)
 | 
			
		||||
 | 
			
		||||
        // Encrypt the symmetric key
 | 
			
		||||
        let encrypted_key = implementation::encrypt_with_key(&key_encryption_key, &symmetric_key)
 | 
			
		||||
            .map_err(|e| CryptoError::EncryptionFailed(e.to_string()))?;
 | 
			
		||||
        
 | 
			
		||||
        // Format: ephemeral_public_key || ciphertext
 | 
			
		||||
        let mut result = ephemeral_public_key.to_encoded_point(false).as_bytes().to_vec();
 | 
			
		||||
        result.extend_from_slice(&ciphertext);
 | 
			
		||||
        
 | 
			
		||||
 | 
			
		||||
        // Format: encrypted_key_length (4 bytes) || encrypted_key || encrypted_message
 | 
			
		||||
        let mut result = Vec::new();
 | 
			
		||||
        let key_len = encrypted_key.len() as u32;
 | 
			
		||||
        result.extend_from_slice(&key_len.to_be_bytes());
 | 
			
		||||
        result.extend_from_slice(&encrypted_key);
 | 
			
		||||
        result.extend_from_slice(&encrypted_message);
 | 
			
		||||
 | 
			
		||||
        Ok(result)
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    /// Decrypts a message using the recipient's private key.
 | 
			
		||||
    /// This is the counterpart to encrypt_asymmetric.
 | 
			
		||||
    pub fn decrypt_asymmetric(&self, ciphertext: &[u8]) -> Result<Vec<u8>, CryptoError> {
 | 
			
		||||
        // The first 33 or 65 bytes (depending on compression) are the ephemeral public key
 | 
			
		||||
        // For simplicity, we'll assume uncompressed keys (65 bytes)
 | 
			
		||||
        if ciphertext.len() <= 65 {
 | 
			
		||||
            return Err(CryptoError::DecryptionFailed("Ciphertext too short".to_string()));
 | 
			
		||||
        // The format is: encrypted_key_length (4 bytes) || encrypted_key || encrypted_message
 | 
			
		||||
        if ciphertext.len() <= 4 {
 | 
			
		||||
            return Err(CryptoError::DecryptionFailed(
 | 
			
		||||
                "Ciphertext too short".to_string(),
 | 
			
		||||
            ));
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        // Extract ephemeral public key and actual ciphertext
 | 
			
		||||
        let ephemeral_public_key = &ciphertext[..65];
 | 
			
		||||
        let actual_ciphertext = &ciphertext[65..];
 | 
			
		||||
        
 | 
			
		||||
        // Parse ephemeral public key
 | 
			
		||||
        let sender_key = VerifyingKey::from_sec1_bytes(ephemeral_public_key)
 | 
			
		||||
            .map_err(|_| CryptoError::InvalidKeyLength)?;
 | 
			
		||||
        
 | 
			
		||||
        // Derive shared secret using ECDH
 | 
			
		||||
        let recipient_secret = EphemeralSecret::random(&mut OsRng);
 | 
			
		||||
        let shared_secret = recipient_secret.diffie_hellman(&sender_key.to_public_key());
 | 
			
		||||
        
 | 
			
		||||
        // Derive decryption key from the shared secret (using the same method as encryption)
 | 
			
		||||
        let decryption_key = {
 | 
			
		||||
 | 
			
		||||
        // Extract the encrypted key length
 | 
			
		||||
        let mut key_len_bytes = [0u8; 4];
 | 
			
		||||
        key_len_bytes.copy_from_slice(&ciphertext[0..4]);
 | 
			
		||||
        let key_len = u32::from_be_bytes(key_len_bytes) as usize;
 | 
			
		||||
 | 
			
		||||
        // Check if the ciphertext is long enough
 | 
			
		||||
        if ciphertext.len() <= 4 + key_len {
 | 
			
		||||
            return Err(CryptoError::DecryptionFailed(
 | 
			
		||||
                "Ciphertext too short".to_string(),
 | 
			
		||||
            ));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Extract the encrypted key and the encrypted message
 | 
			
		||||
        let encrypted_key = &ciphertext[4..4 + key_len];
 | 
			
		||||
        let encrypted_message = &ciphertext[4 + key_len..];
 | 
			
		||||
 | 
			
		||||
        // Decrypt the symmetric key
 | 
			
		||||
        // Use the same key derivation as in encryption
 | 
			
		||||
        let key_encryption_key = {
 | 
			
		||||
            let mut hasher = Sha256::default();
 | 
			
		||||
            hasher.update(shared_secret.raw_secret_bytes());
 | 
			
		||||
            hasher.update(self.verifying_key.to_sec1_bytes());
 | 
			
		||||
            // Use the same fixed salt as in encryption
 | 
			
		||||
            hasher.update(b"fixed_salt_for_testing");
 | 
			
		||||
            hasher.finalize().to_vec()
 | 
			
		||||
        };
 | 
			
		||||
        
 | 
			
		||||
        // Decrypt the message using the derived key
 | 
			
		||||
        implementation::decrypt_with_key(&decryption_key, actual_ciphertext)
 | 
			
		||||
            .map_err(|e| CryptoError::DecryptionFailed(e.to_string()))
 | 
			
		||||
 | 
			
		||||
        // Decrypt the symmetric key
 | 
			
		||||
        let symmetric_key = implementation::decrypt_with_key(&key_encryption_key, encrypted_key)
 | 
			
		||||
            .map_err(|e| CryptoError::DecryptionFailed(format!("Failed to decrypt key: {}", e)))?;
 | 
			
		||||
 | 
			
		||||
        // Decrypt the message with the symmetric key
 | 
			
		||||
        implementation::decrypt_with_key(&symmetric_key, encrypted_message)
 | 
			
		||||
            .map_err(|e| CryptoError::DecryptionFailed(format!("Failed to decrypt message: {}", e)))
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -293,7 +318,7 @@ impl KeySpace {
 | 
			
		||||
        if self.keypairs.contains_key(name) {
 | 
			
		||||
            return Err(CryptoError::KeypairAlreadyExists(name.to_string()));
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
 | 
			
		||||
        let keypair = KeyPair::new(name);
 | 
			
		||||
        self.keypairs.insert(name.to_string(), keypair);
 | 
			
		||||
        Ok(())
 | 
			
		||||
@@ -301,7 +326,9 @@ impl KeySpace {
 | 
			
		||||
 | 
			
		||||
    /// Gets a keypair by name.
 | 
			
		||||
    pub fn get_keypair(&self, name: &str) -> Result<&KeyPair, CryptoError> {
 | 
			
		||||
        self.keypairs.get(name).ok_or(CryptoError::KeypairNotFound(name.to_string()))
 | 
			
		||||
        self.keypairs
 | 
			
		||||
            .get(name)
 | 
			
		||||
            .ok_or(CryptoError::KeypairNotFound(name.to_string()))
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Lists all keypair names in the space.
 | 
			
		||||
@@ -309,4 +336,3 @@ impl KeySpace {
 | 
			
		||||
        self.keypairs.keys().cloned().collect()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,3 @@
 | 
			
		||||
 | 
			
		||||
use crate::vault::keyspace::keypair_types::{KeyPair, KeySpace};
 | 
			
		||||
 | 
			
		||||
#[cfg(test)]
 | 
			
		||||
@@ -20,12 +19,16 @@ mod tests {
 | 
			
		||||
        let signature = keypair.sign(message);
 | 
			
		||||
        assert!(!signature.is_empty());
 | 
			
		||||
 | 
			
		||||
        let is_valid = keypair.verify(message, &signature).expect("Verification failed");
 | 
			
		||||
        let is_valid = keypair
 | 
			
		||||
            .verify(message, &signature)
 | 
			
		||||
            .expect("Verification failed");
 | 
			
		||||
        assert!(is_valid);
 | 
			
		||||
 | 
			
		||||
        // Test with a wrong message
 | 
			
		||||
        let wrong_message = b"This is a different message";
 | 
			
		||||
        let is_valid_wrong = keypair.verify(wrong_message, &signature).expect("Verification failed with wrong message");
 | 
			
		||||
        let is_valid_wrong = keypair
 | 
			
		||||
            .verify(wrong_message, &signature)
 | 
			
		||||
            .expect("Verification failed with wrong message");
 | 
			
		||||
        assert!(!is_valid_wrong);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -36,13 +39,16 @@ mod tests {
 | 
			
		||||
        let signature = keypair.sign(message);
 | 
			
		||||
        let public_key = keypair.pub_key();
 | 
			
		||||
 | 
			
		||||
        let is_valid = KeyPair::verify_with_public_key(&public_key, message, &signature).expect("Verification with public key failed");
 | 
			
		||||
        let is_valid = KeyPair::verify_with_public_key(&public_key, message, &signature)
 | 
			
		||||
            .expect("Verification with public key failed");
 | 
			
		||||
        assert!(is_valid);
 | 
			
		||||
 | 
			
		||||
        // Test with a wrong public key
 | 
			
		||||
        let wrong_keypair = KeyPair::new("wrong_keypair");
 | 
			
		||||
        let wrong_public_key = wrong_keypair.pub_key();
 | 
			
		||||
        let is_valid_wrong_key = KeyPair::verify_with_public_key(&wrong_public_key, message, &signature).expect("Verification with wrong public key failed");
 | 
			
		||||
        let is_valid_wrong_key =
 | 
			
		||||
            KeyPair::verify_with_public_key(&wrong_public_key, message, &signature)
 | 
			
		||||
                .expect("Verification with wrong public key failed");
 | 
			
		||||
        assert!(!is_valid_wrong_key);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -50,7 +56,7 @@ mod tests {
 | 
			
		||||
    fn test_asymmetric_encryption_decryption() {
 | 
			
		||||
        // Sender's keypair
 | 
			
		||||
        let sender_keypair = KeyPair::new("sender");
 | 
			
		||||
        let sender_public_key = sender_keypair.pub_key();
 | 
			
		||||
        let _ = sender_keypair.pub_key();
 | 
			
		||||
 | 
			
		||||
        // Recipient's keypair
 | 
			
		||||
        let recipient_keypair = KeyPair::new("recipient");
 | 
			
		||||
@@ -59,11 +65,15 @@ mod tests {
 | 
			
		||||
        let message = b"This is a secret message";
 | 
			
		||||
 | 
			
		||||
        // Sender encrypts for recipient
 | 
			
		||||
        let ciphertext = sender_keypair.encrypt_asymmetric(&recipient_public_key, message).expect("Encryption failed");
 | 
			
		||||
        let ciphertext = sender_keypair
 | 
			
		||||
            .encrypt_asymmetric(&recipient_public_key, message)
 | 
			
		||||
            .expect("Encryption failed");
 | 
			
		||||
        assert!(!ciphertext.is_empty());
 | 
			
		||||
 | 
			
		||||
        // Recipient decrypts
 | 
			
		||||
        let decrypted_message = recipient_keypair.decrypt_asymmetric(&ciphertext).expect("Decryption failed");
 | 
			
		||||
        let decrypted_message = recipient_keypair
 | 
			
		||||
            .decrypt_asymmetric(&ciphertext)
 | 
			
		||||
            .expect("Decryption failed");
 | 
			
		||||
        assert_eq!(decrypted_message, message);
 | 
			
		||||
 | 
			
		||||
        // Test decryption with wrong keypair
 | 
			
		||||
@@ -75,7 +85,9 @@ mod tests {
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn test_keyspace_add_keypair() {
 | 
			
		||||
        let mut space = KeySpace::new("test_space");
 | 
			
		||||
        space.add_keypair("keypair1").expect("Failed to add keypair1");
 | 
			
		||||
        space
 | 
			
		||||
            .add_keypair("keypair1")
 | 
			
		||||
            .expect("Failed to add keypair1");
 | 
			
		||||
        assert_eq!(space.keypairs.len(), 1);
 | 
			
		||||
        assert!(space.keypairs.contains_key("keypair1"));
 | 
			
		||||
 | 
			
		||||
@@ -83,4 +95,4 @@ mod tests {
 | 
			
		||||
        let result = space.add_keypair("keypair1");
 | 
			
		||||
        assert!(result.is_err());
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,8 +1,8 @@
 | 
			
		||||
use crate::vault::keyspace::keypair_types::KeySpace;
 | 
			
		||||
use crate::vault::keyspace::session_manager::{
 | 
			
		||||
    clear_session, create_keypair, create_space, get_current_space, get_selected_keypair,
 | 
			
		||||
    list_keypairs, select_keypair, set_current_space, SESSION,
 | 
			
		||||
    list_keypairs, select_keypair, set_current_space,
 | 
			
		||||
};
 | 
			
		||||
use crate::vault::keyspace::keypair_types::KeySpace;
 | 
			
		||||
 | 
			
		||||
// Helper function to clear the session before each test
 | 
			
		||||
fn setup_test() {
 | 
			
		||||
@@ -48,7 +48,8 @@ mod tests {
 | 
			
		||||
        assert_eq!(keypair.name, "test_keypair");
 | 
			
		||||
 | 
			
		||||
        select_keypair("test_keypair").expect("Failed to select keypair");
 | 
			
		||||
        let selected_keypair = get_selected_keypair().expect("Failed to get selected keypair after select");
 | 
			
		||||
        let selected_keypair =
 | 
			
		||||
            get_selected_keypair().expect("Failed to get selected keypair after select");
 | 
			
		||||
        assert_eq!(selected_keypair.name, "test_keypair");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,4 @@
 | 
			
		||||
use crate::vault::kvs::store::{create_store, delete_store, open_store, KvStore};
 | 
			
		||||
use std::path::PathBuf;
 | 
			
		||||
use crate::vault::kvs::store::{create_store, delete_store, open_store};
 | 
			
		||||
 | 
			
		||||
// Helper function to generate a unique store name for each test
 | 
			
		||||
fn generate_test_store_name() -> String {
 | 
			
		||||
@@ -102,4 +101,4 @@ mod tests {
 | 
			
		||||
 | 
			
		||||
        cleanup_test_store(&store_name);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user