Simplify and Refactor Asymmetric Encryption/Decryption #10
@ -206,7 +206,7 @@ impl RedisClientWrapper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Select the database
|
// 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);
|
self.initialized.store(true, Ordering::Relaxed);
|
||||||
|
|
||||||
|
@ -1,14 +1,17 @@
|
|||||||
/// Implementation of keypair functionality.
|
|
||||||
|
|
||||||
use k256::ecdsa::{SigningKey, VerifyingKey, signature::{Signer, Verifier}, Signature};
|
|
||||||
use k256::ecdh::EphemeralSecret;
|
use k256::ecdh::EphemeralSecret;
|
||||||
|
/// Implementation of keypair functionality.
|
||||||
|
use k256::ecdsa::{
|
||||||
|
signature::{Signer, Verifier},
|
||||||
|
Signature, SigningKey, VerifyingKey,
|
||||||
|
};
|
||||||
use rand::rngs::OsRng;
|
use rand::rngs::OsRng;
|
||||||
use serde::{Serialize, Deserialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
use sha2::{Digest, Sha256};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use sha2::{Sha256, Digest};
|
|
||||||
|
|
||||||
use crate::vault::symmetric::implementation;
|
|
||||||
use crate::vault::error::CryptoError;
|
use crate::vault::error::CryptoError;
|
||||||
|
use crate::vault::symmetric::implementation;
|
||||||
|
use k256::elliptic_curve::PublicKey;
|
||||||
|
|
||||||
/// A keypair for signing and verifying messages.
|
/// A keypair for signing and verifying messages.
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
@ -23,8 +26,8 @@ pub struct KeyPair {
|
|||||||
// Serialization helpers for VerifyingKey
|
// Serialization helpers for VerifyingKey
|
||||||
mod verifying_key_serde {
|
mod verifying_key_serde {
|
||||||
use super::*;
|
use super::*;
|
||||||
use serde::{Serializer, Deserializer};
|
|
||||||
use serde::de::{self, Visitor};
|
use serde::de::{self, Visitor};
|
||||||
|
use serde::{Deserializer, Serializer};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
pub fn serialize<S>(key: &VerifyingKey, serializer: S) -> Result<S::Ok, S::Error>
|
pub fn serialize<S>(key: &VerifyingKey, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
@ -64,7 +67,7 @@ mod verifying_key_serde {
|
|||||||
while let Some(byte) = seq.next_element()? {
|
while let Some(byte) = seq.next_element()? {
|
||||||
bytes.push(byte);
|
bytes.push(byte);
|
||||||
}
|
}
|
||||||
|
|
||||||
VerifyingKey::from_sec1_bytes(&bytes).map_err(|e| {
|
VerifyingKey::from_sec1_bytes(&bytes).map_err(|e| {
|
||||||
log::error!("Error deserializing verifying key from seq: {:?}", e);
|
log::error!("Error deserializing verifying key from seq: {:?}", e);
|
||||||
de::Error::custom(format!("invalid verifying key from seq: {:?}", e))
|
de::Error::custom(format!("invalid verifying key from seq: {:?}", e))
|
||||||
@ -84,8 +87,8 @@ mod verifying_key_serde {
|
|||||||
// Serialization helpers for SigningKey
|
// Serialization helpers for SigningKey
|
||||||
mod signing_key_serde {
|
mod signing_key_serde {
|
||||||
use super::*;
|
use super::*;
|
||||||
use serde::{Serializer, Deserializer};
|
|
||||||
use serde::de::{self, Visitor};
|
use serde::de::{self, Visitor};
|
||||||
|
use serde::{Deserializer, Serializer};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
pub fn serialize<S>(key: &SigningKey, serializer: S) -> Result<S::Ok, S::Error>
|
pub fn serialize<S>(key: &SigningKey, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
@ -125,7 +128,7 @@ mod signing_key_serde {
|
|||||||
while let Some(byte) = seq.next_element()? {
|
while let Some(byte) = seq.next_element()? {
|
||||||
bytes.push(byte);
|
bytes.push(byte);
|
||||||
}
|
}
|
||||||
|
|
||||||
SigningKey::from_bytes(bytes.as_slice().into()).map_err(|e| {
|
SigningKey::from_bytes(bytes.as_slice().into()).map_err(|e| {
|
||||||
log::error!("Error deserializing signing key from seq: {:?}", e);
|
log::error!("Error deserializing signing key from seq: {:?}", e);
|
||||||
de::Error::custom(format!("invalid signing key from seq: {:?}", e))
|
de::Error::custom(format!("invalid signing key from seq: {:?}", e))
|
||||||
@ -147,7 +150,7 @@ impl KeyPair {
|
|||||||
pub fn new(name: &str) -> Self {
|
pub fn new(name: &str) -> Self {
|
||||||
let signing_key = SigningKey::random(&mut OsRng);
|
let signing_key = SigningKey::random(&mut OsRng);
|
||||||
let verifying_key = VerifyingKey::from(&signing_key);
|
let verifying_key = VerifyingKey::from(&signing_key);
|
||||||
|
|
||||||
KeyPair {
|
KeyPair {
|
||||||
name: name.to_string(),
|
name: name.to_string(),
|
||||||
verifying_key,
|
verifying_key,
|
||||||
@ -159,7 +162,7 @@ impl KeyPair {
|
|||||||
pub fn pub_key(&self) -> Vec<u8> {
|
pub fn pub_key(&self) -> Vec<u8> {
|
||||||
self.verifying_key.to_sec1_bytes().to_vec()
|
self.verifying_key.to_sec1_bytes().to_vec()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Derives a public key from a private key.
|
/// Derives a public key from a private key.
|
||||||
pub fn pub_key_from_private(private_key: &[u8]) -> Result<Vec<u8>, CryptoError> {
|
pub fn pub_key_from_private(private_key: &[u8]) -> Result<Vec<u8>, CryptoError> {
|
||||||
let signing_key = SigningKey::from_bytes(private_key.into())
|
let signing_key = SigningKey::from_bytes(private_key.into())
|
||||||
@ -178,27 +181,31 @@ impl KeyPair {
|
|||||||
pub fn verify(&self, message: &[u8], signature_bytes: &[u8]) -> Result<bool, CryptoError> {
|
pub fn verify(&self, message: &[u8], signature_bytes: &[u8]) -> Result<bool, CryptoError> {
|
||||||
let signature = Signature::from_bytes(signature_bytes.into())
|
let signature = Signature::from_bytes(signature_bytes.into())
|
||||||
.map_err(|e| CryptoError::SignatureFormatError(e.to_string()))?;
|
.map_err(|e| CryptoError::SignatureFormatError(e.to_string()))?;
|
||||||
|
|
||||||
match self.verifying_key.verify(message, &signature) {
|
match self.verifying_key.verify(message, &signature) {
|
||||||
Ok(_) => Ok(true),
|
Ok(_) => Ok(true),
|
||||||
Err(_) => Ok(false), // Verification failed, but operation was successful
|
Err(_) => Ok(false), // Verification failed, but operation was successful
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Verifies a message signature using only a public key.
|
/// 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> {
|
pub fn verify_with_public_key(
|
||||||
let verifying_key = VerifyingKey::from_sec1_bytes(public_key)
|
public_key: &[u8],
|
||||||
.map_err(|_| CryptoError::InvalidKeyLength)?;
|
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())
|
let signature = Signature::from_bytes(signature_bytes.into())
|
||||||
.map_err(|e| CryptoError::SignatureFormatError(e.to_string()))?;
|
.map_err(|e| CryptoError::SignatureFormatError(e.to_string()))?;
|
||||||
|
|
||||||
match verifying_key.verify(message, &signature) {
|
match verifying_key.verify(message, &signature) {
|
||||||
Ok(_) => Ok(true),
|
Ok(_) => Ok(true),
|
||||||
Err(_) => Ok(false), // Verification failed, but operation was successful
|
Err(_) => Ok(false), // Verification failed, but operation was successful
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Encrypts a message using the recipient's public key.
|
/// Encrypts a message using the recipient's public key.
|
||||||
/// This implements ECIES (Elliptic Curve Integrated Encryption Scheme):
|
/// This implements ECIES (Elliptic Curve Integrated Encryption Scheme):
|
||||||
/// 1. Generate an ephemeral keypair
|
/// 1. Generate an ephemeral keypair
|
||||||
@ -206,66 +213,84 @@ impl KeyPair {
|
|||||||
/// 3. Derive encryption key from the shared secret
|
/// 3. Derive encryption key from the shared secret
|
||||||
/// 4. Encrypt the message using symmetric encryption
|
/// 4. Encrypt the message using symmetric encryption
|
||||||
/// 5. Return the ephemeral public key and the ciphertext
|
/// 5. Return the ephemeral public key and the ciphertext
|
||||||
pub fn encrypt_asymmetric(&self, recipient_public_key: &[u8], message: &[u8]) -> Result<Vec<u8>, CryptoError> {
|
pub fn encrypt_asymmetric(
|
||||||
|
&self,
|
||||||
|
recipient_public_key: &[u8],
|
||||||
|
message: &[u8],
|
||||||
|
) -> Result<Vec<u8>, CryptoError> {
|
||||||
// Parse recipient's public key
|
// Parse recipient's public key
|
||||||
let recipient_key = VerifyingKey::from_sec1_bytes(recipient_public_key)
|
let recipient_key = VerifyingKey::from_sec1_bytes(recipient_public_key)
|
||||||
.map_err(|_| CryptoError::InvalidKeyLength)?;
|
.map_err(|_| CryptoError::InvalidKeyLength)?;
|
||||||
|
|
||||||
|
// Convert ecdsa VerifyingKey to k256 PublicKey
|
||||||
|
let recipient_public_key_k256 =
|
||||||
|
PublicKey::from_sec1_bytes(&recipient_key.to_encoded_point(false).as_bytes())
|
||||||
|
.map_err(|_| CryptoError::InvalidKeyLength)?;
|
||||||
|
|
||||||
// Generate ephemeral keypair
|
// Generate ephemeral keypair
|
||||||
let ephemeral_signing_key = SigningKey::random(&mut OsRng);
|
let ephemeral_signing_key = SigningKey::random(&mut OsRng);
|
||||||
let ephemeral_public_key = VerifyingKey::from(&ephemeral_signing_key);
|
let ephemeral_public_key = VerifyingKey::from(&ephemeral_signing_key);
|
||||||
|
|
||||||
// Derive shared secret using ECDH
|
// Derive shared secret using ECDH
|
||||||
let ephemeral_secret = EphemeralSecret::random(&mut OsRng);
|
let ephemeral_secret = EphemeralSecret::random(&mut OsRng);
|
||||||
let shared_secret = ephemeral_secret.diffie_hellman(&recipient_key.to_public_key());
|
let shared_secret = ephemeral_secret.diffie_hellman(&recipient_public_key_k256);
|
||||||
|
|
||||||
// Derive encryption key from the shared secret (e.g., using HKDF or hashing)
|
// 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 = {
|
let encryption_key = {
|
||||||
let mut hasher = Sha256::default();
|
let mut hasher = Sha256::default();
|
||||||
hasher.update(shared_secret.raw_secret_bytes());
|
hasher.update(shared_secret.raw_secret_bytes());
|
||||||
hasher.finalize().to_vec()
|
hasher.finalize().to_vec()
|
||||||
};
|
};
|
||||||
|
|
||||||
// Encrypt the message using the derived key
|
// Encrypt the message using the derived key
|
||||||
let ciphertext = implementation::encrypt_with_key(&encryption_key, message)
|
let ciphertext = implementation::encrypt_with_key(&encryption_key, message)
|
||||||
.map_err(|e| CryptoError::EncryptionFailed(e.to_string()))?;
|
.map_err(|e| CryptoError::EncryptionFailed(e.to_string()))?;
|
||||||
|
|
||||||
// Format: ephemeral_public_key || ciphertext
|
// Format: ephemeral_public_key || ciphertext
|
||||||
let mut result = ephemeral_public_key.to_encoded_point(false).as_bytes().to_vec();
|
let mut result = ephemeral_public_key
|
||||||
|
.to_encoded_point(false)
|
||||||
|
.as_bytes()
|
||||||
|
.to_vec();
|
||||||
result.extend_from_slice(&ciphertext);
|
result.extend_from_slice(&ciphertext);
|
||||||
|
|
||||||
Ok(result)
|
Ok(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Decrypts a message using the recipient's private key.
|
/// Decrypts a message using the recipient's private key.
|
||||||
/// This is the counterpart to encrypt_asymmetric.
|
/// This is the counterpart to encrypt_asymmetric.
|
||||||
pub fn decrypt_asymmetric(&self, ciphertext: &[u8]) -> Result<Vec<u8>, CryptoError> {
|
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
|
// The first 33 or 65 bytes (depending on compression) are the ephemeral public key
|
||||||
// For simplicity, we'll assume uncompressed keys (65 bytes)
|
// For simplicity, we'll assume uncompressed keys (65 bytes)
|
||||||
if ciphertext.len() <= 65 {
|
if ciphertext.len() <= 65 {
|
||||||
return Err(CryptoError::DecryptionFailed("Ciphertext too short".to_string()));
|
return Err(CryptoError::DecryptionFailed(
|
||||||
|
"Ciphertext too short".to_string(),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extract ephemeral public key and actual ciphertext
|
// Extract ephemeral public key and actual ciphertext
|
||||||
let ephemeral_public_key = &ciphertext[..65];
|
let ephemeral_public_key = &ciphertext[..65];
|
||||||
let actual_ciphertext = &ciphertext[65..];
|
let actual_ciphertext = &ciphertext[65..];
|
||||||
|
|
||||||
// Parse ephemeral public key
|
// Parse ephemeral public key
|
||||||
let sender_key = VerifyingKey::from_sec1_bytes(ephemeral_public_key)
|
let sender_key = VerifyingKey::from_sec1_bytes(ephemeral_public_key)
|
||||||
.map_err(|_| CryptoError::InvalidKeyLength)?;
|
.map_err(|_| CryptoError::InvalidKeyLength)?;
|
||||||
|
|
||||||
|
// Convert ecdsa VerifyingKey to k256 PublicKey
|
||||||
|
let sender_public_key_k256 =
|
||||||
|
PublicKey::from_sec1_bytes(&sender_key.to_encoded_point(false).as_bytes())
|
||||||
|
.map_err(|_| CryptoError::InvalidKeyLength)?;
|
||||||
|
|
||||||
// Derive shared secret using ECDH
|
// Derive shared secret using ECDH
|
||||||
let recipient_secret = EphemeralSecret::random(&mut OsRng);
|
let recipient_secret = EphemeralSecret::random(&mut OsRng);
|
||||||
let shared_secret = recipient_secret.diffie_hellman(&sender_key.to_public_key());
|
let shared_secret = recipient_secret.diffie_hellman(&sender_public_key_k256);
|
||||||
|
|
||||||
// Derive decryption key from the shared secret (using the same method as encryption)
|
// Derive decryption key from the shared secret (using the same method as encryption)
|
||||||
let decryption_key = {
|
let decryption_key = {
|
||||||
let mut hasher = Sha256::default();
|
let mut hasher = Sha256::default();
|
||||||
hasher.update(shared_secret.raw_secret_bytes());
|
hasher.update(shared_secret.raw_secret_bytes());
|
||||||
hasher.finalize().to_vec()
|
hasher.finalize().to_vec()
|
||||||
};
|
};
|
||||||
|
|
||||||
// Decrypt the message using the derived key
|
// Decrypt the message using the derived key
|
||||||
implementation::decrypt_with_key(&decryption_key, actual_ciphertext)
|
implementation::decrypt_with_key(&decryption_key, actual_ciphertext)
|
||||||
.map_err(|e| CryptoError::DecryptionFailed(e.to_string()))
|
.map_err(|e| CryptoError::DecryptionFailed(e.to_string()))
|
||||||
@ -293,7 +318,7 @@ impl KeySpace {
|
|||||||
if self.keypairs.contains_key(name) {
|
if self.keypairs.contains_key(name) {
|
||||||
return Err(CryptoError::KeypairAlreadyExists(name.to_string()));
|
return Err(CryptoError::KeypairAlreadyExists(name.to_string()));
|
||||||
}
|
}
|
||||||
|
|
||||||
let keypair = KeyPair::new(name);
|
let keypair = KeyPair::new(name);
|
||||||
self.keypairs.insert(name.to_string(), keypair);
|
self.keypairs.insert(name.to_string(), keypair);
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -301,7 +326,9 @@ impl KeySpace {
|
|||||||
|
|
||||||
/// Gets a keypair by name.
|
/// Gets a keypair by name.
|
||||||
pub fn get_keypair(&self, name: &str) -> Result<&KeyPair, CryptoError> {
|
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.
|
/// Lists all keypair names in the space.
|
||||||
@ -309,4 +336,3 @@ impl KeySpace {
|
|||||||
self.keypairs.keys().cloned().collect()
|
self.keypairs.keys().cloned().collect()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user