This commit is contained in:
2025-04-19 19:16:58 +02:00
parent 8d707e61a2
commit 66555fcb0d
13 changed files with 2374 additions and 794 deletions

View File

@@ -1,29 +1,76 @@
//! Public API for keypair operations.
use crate::core::keypair;
use crate::core::symmetric;
use crate::core::error::CryptoError;
/// Initializes a new keypair for signing and verification.
/// Creates a new key space with the given name.
///
/// # Arguments
///
/// * `name` - The name of the key space.
///
/// # Returns
///
/// * `Ok(())` if the keypair was initialized successfully.
/// * `Err(CryptoError::KeypairAlreadyInitialized)` if a keypair was already initialized.
pub fn new() -> Result<(), CryptoError> {
keypair::keypair_new()
/// * `Ok(())` if the key space was created successfully.
/// * `Err(CryptoError)` if an error occurred.
pub fn create_space(name: &str) -> Result<(), CryptoError> {
keypair::create_space(name)
}
/// Gets the public key of the initialized keypair.
/// Creates a new keypair in the current space.
///
/// # Arguments
///
/// * `name` - The name of the keypair.
///
/// # Returns
///
/// * `Ok(())` if the keypair was created successfully.
/// * `Err(CryptoError::NoActiveSpace)` if no space is active.
/// * `Err(CryptoError::KeypairAlreadyExists)` if a keypair with this name already exists.
pub fn create_keypair(name: &str) -> Result<(), CryptoError> {
keypair::create_keypair(name)
}
/// Selects a keypair for use.
///
/// # Arguments
///
/// * `name` - The name of the keypair to select.
///
/// # Returns
///
/// * `Ok(())` if the keypair was selected successfully.
/// * `Err(CryptoError::NoActiveSpace)` if no space is active.
/// * `Err(CryptoError::KeypairNotFound)` if the keypair was not found.
pub fn select_keypair(name: &str) -> Result<(), CryptoError> {
keypair::select_keypair(name)
}
/// Lists all keypair names in the current space.
///
/// # Returns
///
/// * `Ok(Vec<String>)` containing the keypair names.
/// * `Err(CryptoError::NoActiveSpace)` if no space is active.
pub fn list_keypairs() -> Result<Vec<String>, CryptoError> {
keypair::list_keypairs()
}
/// Gets the public key of the selected keypair.
///
/// # Returns
///
/// * `Ok(Vec<u8>)` containing the public key bytes.
/// * `Err(CryptoError::KeypairNotInitialized)` if no keypair has been initialized.
/// * `Err(CryptoError::NoActiveSpace)` if no space is active.
/// * `Err(CryptoError::NoKeypairSelected)` if no keypair is selected.
/// * `Err(CryptoError::KeypairNotFound)` if the selected keypair was not found.
pub fn pub_key() -> Result<Vec<u8>, CryptoError> {
keypair::keypair_pub_key()
}
/// Signs a message using the initialized keypair.
/// Signs a message using the selected keypair.
///
/// # Arguments
///
@@ -32,7 +79,9 @@ pub fn pub_key() -> Result<Vec<u8>, CryptoError> {
/// # Returns
///
/// * `Ok(Vec<u8>)` containing the signature bytes.
/// * `Err(CryptoError::KeypairNotInitialized)` if no keypair has been initialized.
/// * `Err(CryptoError::NoActiveSpace)` if no space is active.
/// * `Err(CryptoError::NoKeypairSelected)` if no keypair is selected.
/// * `Err(CryptoError::KeypairNotFound)` if the selected keypair was not found.
pub fn sign(message: &[u8]) -> Result<Vec<u8>, CryptoError> {
keypair::keypair_sign(message)
}
@@ -48,8 +97,49 @@ pub fn sign(message: &[u8]) -> Result<Vec<u8>, CryptoError> {
///
/// * `Ok(true)` if the signature is valid.
/// * `Ok(false)` if the signature is invalid.
/// * `Err(CryptoError::KeypairNotInitialized)` if no keypair has been initialized.
/// * `Err(CryptoError::NoActiveSpace)` if no space is active.
/// * `Err(CryptoError::NoKeypairSelected)` if no keypair is selected.
/// * `Err(CryptoError::KeypairNotFound)` if the selected keypair was not found.
/// * `Err(CryptoError::SignatureFormatError)` if the signature format is invalid.
pub fn verify(message: &[u8], signature: &[u8]) -> Result<bool, CryptoError> {
keypair::keypair_verify(message, signature)
}
/// Encrypts a key space with a password.
///
/// # Arguments
///
/// * `password` - The password to encrypt with.
///
/// # Returns
///
/// * `Ok(String)` containing the serialized encrypted key space.
/// * `Err(CryptoError::NoActiveSpace)` if no space is active.
/// * `Err(CryptoError)` if encryption fails.
pub fn encrypt_space(password: &str) -> Result<String, CryptoError> {
let space = keypair::get_current_space()?;
let encrypted = symmetric::encrypt_key_space(&space, password)?;
symmetric::serialize_encrypted_space(&encrypted)
}
/// Decrypts a key space with a password and sets it as the current space.
///
/// # Arguments
///
/// * `encrypted_space` - The serialized encrypted key space.
/// * `password` - The password to decrypt with.
///
/// # Returns
///
/// * `Ok(())` if the key space was decrypted and set successfully.
/// * `Err(CryptoError)` if decryption fails.
pub fn decrypt_space(encrypted_space: &str, password: &str) -> Result<(), CryptoError> {
let encrypted = symmetric::deserialize_encrypted_space(encrypted_space)?;
let space = symmetric::decrypt_key_space(&encrypted, password)?;
keypair::set_current_space(space)
}
/// Clears the current session (logout).
pub fn logout() {
keypair::clear_session();
}

View File

@@ -12,6 +12,19 @@ pub fn generate_key() -> [u8; 32] {
symmetric::generate_symmetric_key()
}
/// Derives a 32-byte key from a password.
///
/// # Arguments
///
/// * `password` - The password to derive the key from.
///
/// # Returns
///
/// A 32-byte array containing the derived key.
pub fn derive_key_from_password(password: &str) -> [u8; 32] {
symmetric::derive_key_from_password(password)
}
/// Encrypts data using ChaCha20Poly1305.
///
/// A random nonce is generated internally and appended to the ciphertext.
@@ -46,4 +59,40 @@ pub fn encrypt(key: &[u8], message: &[u8]) -> Result<Vec<u8>, CryptoError> {
/// * `Err(CryptoError::DecryptionFailed)` if decryption fails or the ciphertext is too short.
pub fn decrypt(key: &[u8], ciphertext: &[u8]) -> Result<Vec<u8>, CryptoError> {
symmetric::decrypt_symmetric(key, ciphertext)
}
/// Encrypts data using a password.
///
/// The password is used to derive a key, which is then used to encrypt the data.
///
/// # Arguments
///
/// * `password` - The password to encrypt with.
/// * `message` - The message to encrypt.
///
/// # Returns
///
/// * `Ok(Vec<u8>)` containing the ciphertext.
/// * `Err(CryptoError)` if encryption fails.
pub fn encrypt_with_password(password: &str, message: &[u8]) -> Result<Vec<u8>, CryptoError> {
let key = symmetric::derive_key_from_password(password);
symmetric::encrypt_symmetric(&key, message)
}
/// Decrypts data using a password.
///
/// The password is used to derive a key, which is then used to decrypt the data.
///
/// # Arguments
///
/// * `password` - The password to decrypt with.
/// * `ciphertext` - The ciphertext to decrypt.
///
/// # Returns
///
/// * `Ok(Vec<u8>)` containing the decrypted message.
/// * `Err(CryptoError)` if decryption fails.
pub fn decrypt_with_password(password: &str, ciphertext: &[u8]) -> Result<Vec<u8>, CryptoError> {
let key = symmetric::derive_key_from_password(password);
symmetric::decrypt_symmetric(&key, ciphertext)
}

View File

@@ -18,6 +18,22 @@ pub enum CryptoError {
DecryptionFailed,
/// The key length is invalid.
InvalidKeyLength,
/// No space is currently active.
NoActiveSpace,
/// No keypair is currently selected.
NoKeypairSelected,
/// The specified keypair was not found.
KeypairNotFound,
/// A keypair with this name already exists.
KeypairAlreadyExists,
/// The space with the given name was not found.
SpaceNotFound,
/// A space with this name already exists.
SpaceAlreadyExists,
/// Invalid password for the space.
InvalidPassword,
/// Error during serialization or deserialization.
SerializationError,
/// Other error with description.
#[allow(dead_code)]
Other(String),
@@ -33,6 +49,14 @@ impl std::fmt::Display for CryptoError {
CryptoError::EncryptionFailed => write!(f, "Encryption failed"),
CryptoError::DecryptionFailed => write!(f, "Decryption failed"),
CryptoError::InvalidKeyLength => write!(f, "Invalid key length"),
CryptoError::NoActiveSpace => write!(f, "No active space"),
CryptoError::NoKeypairSelected => write!(f, "No keypair selected"),
CryptoError::KeypairNotFound => write!(f, "Keypair not found"),
CryptoError::KeypairAlreadyExists => write!(f, "Keypair already exists"),
CryptoError::SpaceNotFound => write!(f, "Space not found"),
CryptoError::SpaceAlreadyExists => write!(f, "Space already exists"),
CryptoError::InvalidPassword => write!(f, "Invalid password"),
CryptoError::SerializationError => write!(f, "Serialization error"),
CryptoError::Other(s) => write!(f, "Crypto error: {}", s),
}
}
@@ -50,6 +74,14 @@ pub fn error_to_status_code(err: CryptoError) -> i32 {
CryptoError::EncryptionFailed => -5,
CryptoError::DecryptionFailed => -6,
CryptoError::InvalidKeyLength => -7,
CryptoError::NoActiveSpace => -8,
CryptoError::NoKeypairSelected => -9,
CryptoError::KeypairNotFound => -10,
CryptoError::KeypairAlreadyExists => -11,
CryptoError::SpaceNotFound => -12,
CryptoError::SpaceAlreadyExists => -13,
CryptoError::InvalidPassword => -14,
CryptoError::SerializationError => -15,
CryptoError::Other(_) => -99,
}
}

View File

@@ -1,87 +1,312 @@
//! Core implementation of keypair functionality.
use k256::ecdsa::{SigningKey, VerifyingKey, signature::{Signer, Verifier}, Signature};
use once_cell::sync::OnceCell;
use rand::rngs::OsRng;
use serde::{Serialize, Deserialize};
use std::collections::HashMap;
use once_cell::sync::Lazy;
use std::sync::Mutex;
use super::error::CryptoError;
/// A keypair for signing and verifying messages.
#[derive(Debug)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct KeyPair {
pub name: String,
#[serde(with = "verifying_key_serde")]
pub verifying_key: VerifyingKey,
#[serde(with = "signing_key_serde")]
pub signing_key: SigningKey,
}
/// Global keypair instance.
pub static KEYPAIR: OnceCell<KeyPair> = OnceCell::new();
// Serialization helpers for VerifyingKey
mod verifying_key_serde {
use super::*;
use serde::{Serializer, Deserializer};
use serde::de::{self, Visitor};
use std::fmt;
/// Initializes the global keypair.
///
/// # Returns
///
/// * `Ok(())` if the keypair was initialized successfully.
/// * `Err(CryptoError::KeypairAlreadyInitialized)` if the keypair was already initialized.
pub fn keypair_new() -> Result<(), CryptoError> {
let signing_key = SigningKey::random(&mut OsRng);
let verifying_key = VerifyingKey::from(&signing_key);
let keypair = KeyPair { verifying_key, signing_key };
KEYPAIR.set(keypair).map_err(|_| CryptoError::KeypairAlreadyInitialized)
}
/// Gets the public key bytes.
///
/// # Returns
///
/// * `Ok(Vec<u8>)` containing the public key bytes.
/// * `Err(CryptoError::KeypairNotInitialized)` if the keypair has not been initialized.
pub fn keypair_pub_key() -> Result<Vec<u8>, CryptoError> {
KEYPAIR.get()
.ok_or(CryptoError::KeypairNotInitialized)
.map(|kp| kp.verifying_key.to_sec1_bytes().to_vec())
}
/// Signs a message.
///
/// # Arguments
///
/// * `message` - The message to sign.
///
/// # Returns
///
/// * `Ok(Vec<u8>)` containing the signature bytes.
/// * `Err(CryptoError::KeypairNotInitialized)` if the keypair has not been initialized.
pub fn keypair_sign(message: &[u8]) -> Result<Vec<u8>, CryptoError> {
KEYPAIR.get()
.ok_or(CryptoError::KeypairNotInitialized)
.map(|kp| {
let signature: Signature = kp.signing_key.sign(message);
signature.to_bytes().to_vec()
})
}
/// Verifies a message signature.
///
/// # Arguments
///
/// * `message` - The message that was signed.
/// * `signature_bytes` - The signature to verify.
///
/// # Returns
///
/// * `Ok(true)` if the signature is valid.
/// * `Ok(false)` if the signature is invalid.
/// * `Err(CryptoError::KeypairNotInitialized)` if the keypair has not been initialized.
/// * `Err(CryptoError::SignatureFormatError)` if the signature format is invalid.
pub fn keypair_verify(message: &[u8], signature_bytes: &[u8]) -> Result<bool, CryptoError> {
let keypair = KEYPAIR.get().ok_or(CryptoError::KeypairNotInitialized)?;
let signature = Signature::from_bytes(signature_bytes.into())
.map_err(|_| CryptoError::SignatureFormatError)?;
match keypair.verifying_key.verify(message, &signature) {
Ok(_) => Ok(true),
Err(_) => Ok(false), // Verification failed, but operation was successful
pub fn serialize<S>(key: &VerifyingKey, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let bytes = key.to_sec1_bytes();
serializer.serialize_bytes(&bytes)
}
struct VerifyingKeyVisitor;
impl<'de> Visitor<'de> for VerifyingKeyVisitor {
type Value = VerifyingKey;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("a byte array representing a verifying key")
}
fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E>
where
E: de::Error,
{
VerifyingKey::from_sec1_bytes(v).map_err(|_| E::custom("invalid verifying key"))
}
}
pub fn deserialize<'de, D>(deserializer: D) -> Result<VerifyingKey, D::Error>
where
D: Deserializer<'de>,
{
deserializer.deserialize_bytes(VerifyingKeyVisitor)
}
}
// Serialization helpers for SigningKey
mod signing_key_serde {
use super::*;
use serde::{Serializer, Deserializer};
use serde::de::{self, Visitor};
use std::fmt;
pub fn serialize<S>(key: &SigningKey, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let bytes = key.to_bytes();
serializer.serialize_bytes(&bytes)
}
struct SigningKeyVisitor;
impl<'de> Visitor<'de> for SigningKeyVisitor {
type Value = SigningKey;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("a byte array representing a signing key")
}
fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E>
where
E: de::Error,
{
SigningKey::from_bytes(v.into()).map_err(|_| E::custom("invalid signing key"))
}
}
pub fn deserialize<'de, D>(deserializer: D) -> Result<SigningKey, D::Error>
where
D: Deserializer<'de>,
{
deserializer.deserialize_bytes(SigningKeyVisitor)
}
}
impl KeyPair {
/// Creates a new keypair with the given name.
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,
signing_key,
}
}
/// Gets the public key bytes.
pub fn pub_key(&self) -> Vec<u8> {
self.verifying_key.to_sec1_bytes().to_vec()
}
/// Signs a message.
pub fn sign(&self, message: &[u8]) -> Vec<u8> {
let signature: Signature = self.signing_key.sign(message);
signature.to_bytes().to_vec()
}
/// Verifies a message signature.
pub fn verify(&self, message: &[u8], signature_bytes: &[u8]) -> Result<bool, CryptoError> {
let signature = Signature::from_bytes(signature_bytes.into())
.map_err(|_| CryptoError::SignatureFormatError)?;
match self.verifying_key.verify(message, &signature) {
Ok(_) => Ok(true),
Err(_) => Ok(false), // Verification failed, but operation was successful
}
}
}
/// A collection of keypairs.
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct KeySpace {
pub name: String,
pub keypairs: HashMap<String, KeyPair>,
}
impl KeySpace {
/// Creates a new key space with the given name.
pub fn new(name: &str) -> Self {
KeySpace {
name: name.to_string(),
keypairs: HashMap::new(),
}
}
/// Adds a new keypair to the space.
pub fn add_keypair(&mut self, name: &str) -> Result<(), CryptoError> {
if self.keypairs.contains_key(name) {
return Err(CryptoError::KeypairAlreadyExists);
}
let keypair = KeyPair::new(name);
self.keypairs.insert(name.to_string(), keypair);
Ok(())
}
/// Gets a keypair by name.
pub fn get_keypair(&self, name: &str) -> Result<&KeyPair, CryptoError> {
self.keypairs.get(name).ok_or(CryptoError::KeypairNotFound)
}
/// Lists all keypair names in the space.
pub fn list_keypairs(&self) -> Vec<String> {
self.keypairs.keys().cloned().collect()
}
}
/// Session state for the current key space and selected keypair.
pub struct Session {
pub current_space: Option<KeySpace>,
pub selected_keypair: Option<String>,
}
impl Default for Session {
fn default() -> Self {
Session {
current_space: None,
selected_keypair: None,
}
}
}
/// Global session state.
static SESSION: Lazy<Mutex<Session>> = Lazy::new(|| {
Mutex::new(Session::default())
});
/// Creates a new key space with the given name.
pub fn create_space(name: &str) -> Result<(), CryptoError> {
let mut session = SESSION.lock().unwrap();
// Create a new space
let space = KeySpace::new(name);
// Set as current space
session.current_space = Some(space);
session.selected_keypair = None;
Ok(())
}
/// Sets the current key space.
pub fn set_current_space(space: KeySpace) -> Result<(), CryptoError> {
let mut session = SESSION.lock().unwrap();
session.current_space = Some(space);
session.selected_keypair = None;
Ok(())
}
/// Gets the current key space.
pub fn get_current_space() -> Result<KeySpace, CryptoError> {
let session = SESSION.lock().unwrap();
session.current_space.clone().ok_or(CryptoError::NoActiveSpace)
}
/// Clears the current session (logout).
pub fn clear_session() {
let mut session = SESSION.lock().unwrap();
session.current_space = None;
session.selected_keypair = None;
}
/// Creates a new keypair in the current space.
pub fn create_keypair(name: &str) -> Result<(), CryptoError> {
let mut session = SESSION.lock().unwrap();
if let Some(ref mut space) = session.current_space {
if space.keypairs.contains_key(name) {
return Err(CryptoError::KeypairAlreadyExists);
}
let keypair = KeyPair::new(name);
space.keypairs.insert(name.to_string(), keypair);
// Automatically select the new keypair
session.selected_keypair = Some(name.to_string());
Ok(())
} else {
Err(CryptoError::NoActiveSpace)
}
}
/// Selects a keypair for use.
pub fn select_keypair(name: &str) -> Result<(), CryptoError> {
let mut session = SESSION.lock().unwrap();
if let Some(ref space) = session.current_space {
if !space.keypairs.contains_key(name) {
return Err(CryptoError::KeypairNotFound);
}
session.selected_keypair = Some(name.to_string());
Ok(())
} else {
Err(CryptoError::NoActiveSpace)
}
}
/// Gets the currently selected keypair.
pub fn get_selected_keypair() -> Result<KeyPair, CryptoError> {
let session = SESSION.lock().unwrap();
if let Some(ref space) = session.current_space {
if let Some(ref keypair_name) = session.selected_keypair {
if let Some(keypair) = space.keypairs.get(keypair_name) {
return Ok(keypair.clone());
}
return Err(CryptoError::KeypairNotFound);
}
return Err(CryptoError::NoKeypairSelected);
}
Err(CryptoError::NoActiveSpace)
}
/// Lists all keypair names in the current space.
pub fn list_keypairs() -> Result<Vec<String>, CryptoError> {
let session = SESSION.lock().unwrap();
if let Some(ref space) = session.current_space {
Ok(space.keypairs.keys().cloned().collect())
} else {
Err(CryptoError::NoActiveSpace)
}
}
/// Gets the public key of the selected keypair.
pub fn keypair_pub_key() -> Result<Vec<u8>, CryptoError> {
let keypair = get_selected_keypair()?;
Ok(keypair.pub_key())
}
/// Signs a message with the selected keypair.
pub fn keypair_sign(message: &[u8]) -> Result<Vec<u8>, CryptoError> {
let keypair = get_selected_keypair()?;
Ok(keypair.sign(message))
}
/// Verifies a message signature with the selected keypair.
pub fn keypair_verify(message: &[u8], signature_bytes: &[u8]) -> Result<bool, CryptoError> {
let keypair = get_selected_keypair()?;
keypair.verify(message, signature_bytes)
}

View File

@@ -3,8 +3,11 @@
use chacha20poly1305::{ChaCha20Poly1305, KeyInit, Nonce};
use chacha20poly1305::aead::Aead;
use rand::{rngs::OsRng, RngCore};
use serde::{Serialize, Deserialize};
use sha2::{Sha256, Digest};
use super::error::CryptoError;
use super::keypair::KeySpace;
/// The size of the nonce in bytes.
const NONCE_SIZE: usize = 12;
@@ -20,6 +23,25 @@ pub fn generate_symmetric_key() -> [u8; 32] {
key
}
/// Derives a 32-byte key from a password.
///
/// # Arguments
///
/// * `password` - The password to derive the key from.
///
/// # Returns
///
/// A 32-byte array containing the derived key.
pub fn derive_key_from_password(password: &str) -> [u8; 32] {
let mut hasher = Sha256::new();
hasher.update(password.as_bytes());
let result = hasher.finalize();
let mut key = [0u8; 32];
key.copy_from_slice(&result);
key
}
/// Encrypts data using ChaCha20Poly1305 with an internally generated nonce.
///
/// The nonce is appended to the ciphertext so it can be extracted during decryption.
@@ -87,4 +109,110 @@ pub fn decrypt_symmetric(key: &[u8], ciphertext_with_nonce: &[u8]) -> Result<Vec
// Decrypt message
cipher.decrypt(nonce, ciphertext)
.map_err(|_| CryptoError::DecryptionFailed)
}
/// Metadata for an encrypted key space.
#[derive(Serialize, Deserialize)]
pub struct EncryptedKeySpaceMetadata {
pub name: String,
pub created_at: u64,
pub last_accessed: u64,
}
/// An encrypted key space with metadata.
#[derive(Serialize, Deserialize)]
pub struct EncryptedKeySpace {
pub metadata: EncryptedKeySpaceMetadata,
pub encrypted_data: Vec<u8>,
}
/// Encrypts a key space using a password.
///
/// # Arguments
///
/// * `space` - The key space to encrypt.
/// * `password` - The password to encrypt with.
///
/// # Returns
///
/// * `Ok(EncryptedKeySpace)` containing the encrypted key space.
/// * `Err(CryptoError)` if encryption fails.
pub fn encrypt_key_space(space: &KeySpace, password: &str) -> Result<EncryptedKeySpace, CryptoError> {
// Serialize the key space
let serialized = serde_json::to_vec(space)
.map_err(|_| CryptoError::SerializationError)?;
// Derive key from password
let key = derive_key_from_password(password);
// Encrypt the serialized data
let encrypted_data = encrypt_symmetric(&key, &serialized)?;
// Create metadata
let now = js_sys::Date::now() as u64;
let metadata = EncryptedKeySpaceMetadata {
name: space.name.clone(),
created_at: now,
last_accessed: now,
};
Ok(EncryptedKeySpace {
metadata,
encrypted_data,
})
}
/// Decrypts a key space using a password.
///
/// # Arguments
///
/// * `encrypted_space` - The encrypted key space.
/// * `password` - The password to decrypt with.
///
/// # Returns
///
/// * `Ok(KeySpace)` containing the decrypted key space.
/// * `Err(CryptoError)` if decryption fails.
pub fn decrypt_key_space(encrypted_space: &EncryptedKeySpace, password: &str) -> Result<KeySpace, CryptoError> {
// Derive key from password
let key = derive_key_from_password(password);
// Decrypt the data
let decrypted_data = decrypt_symmetric(&key, &encrypted_space.encrypted_data)?;
// Deserialize the key space
let space: KeySpace = serde_json::from_slice(&decrypted_data)
.map_err(|_| CryptoError::SerializationError)?;
Ok(space)
}
/// Serializes an encrypted key space to a JSON string.
///
/// # Arguments
///
/// * `encrypted_space` - The encrypted key space to serialize.
///
/// # Returns
///
/// * `Ok(String)` containing the serialized encrypted key space.
/// * `Err(CryptoError)` if serialization fails.
pub fn serialize_encrypted_space(encrypted_space: &EncryptedKeySpace) -> Result<String, CryptoError> {
serde_json::to_string(encrypted_space)
.map_err(|_| CryptoError::SerializationError)
}
/// Deserializes an encrypted key space from a JSON string.
///
/// # Arguments
///
/// * `serialized` - The serialized encrypted key space.
///
/// # Returns
///
/// * `Ok(EncryptedKeySpace)` containing the deserialized encrypted key space.
/// * `Err(CryptoError)` if deserialization fails.
pub fn deserialize_encrypted_space(serialized: &str) -> Result<EncryptedKeySpace, CryptoError> {
serde_json::from_str(serialized)
.map_err(|_| CryptoError::SerializationError)
}

View File

@@ -26,16 +26,60 @@ pub fn main_js() -> Result<(), JsValue> {
Ok(())
}
// --- WebAssembly Exports ---
// --- WebAssembly Exports for Key Space Management ---
#[wasm_bindgen]
pub fn keypair_new() -> i32 {
match keypair::new() {
pub fn create_key_space(name: &str) -> i32 {
match keypair::create_space(name) {
Ok(_) => 0, // Success
Err(e) => error_to_status_code(e),
}
}
#[wasm_bindgen]
pub fn encrypt_key_space(password: &str) -> Result<String, JsValue> {
keypair::encrypt_space(password)
.map_err(|e| JsValue::from_str(&e.to_string()))
}
#[wasm_bindgen]
pub fn decrypt_key_space(encrypted_space: &str, password: &str) -> i32 {
match keypair::decrypt_space(encrypted_space, password) {
Ok(_) => 0, // Success
Err(e) => error_to_status_code(e),
}
}
#[wasm_bindgen]
pub fn logout() {
keypair::logout();
}
// --- WebAssembly Exports for Keypair Management ---
#[wasm_bindgen]
pub fn create_keypair(name: &str) -> i32 {
match keypair::create_keypair(name) {
Ok(_) => 0, // Success
Err(e) => error_to_status_code(e),
}
}
#[wasm_bindgen]
pub fn select_keypair(name: &str) -> i32 {
match keypair::select_keypair(name) {
Ok(_) => 0, // Success
Err(e) => error_to_status_code(e),
}
}
#[wasm_bindgen]
pub fn list_keypairs() -> Result<Vec<JsValue>, JsValue> {
keypair::list_keypairs()
.map(|names| names.into_iter().map(JsValue::from).collect())
.map_err(|e| JsValue::from_str(&e.to_string()))
}
#[wasm_bindgen]
pub fn keypair_pub_key() -> Result<Vec<u8>, JsValue> {
keypair::pub_key()
@@ -54,11 +98,18 @@ pub fn keypair_verify(message: &[u8], signature: &[u8]) -> Result<bool, JsValue>
.map_err(|e| JsValue::from_str(&e.to_string()))
}
// --- WebAssembly Exports for Symmetric Encryption ---
#[wasm_bindgen]
pub fn generate_symmetric_key() -> Vec<u8> {
symmetric::generate_key().to_vec()
}
#[wasm_bindgen]
pub fn derive_key_from_password(password: &str) -> Vec<u8> {
symmetric::derive_key_from_password(password).to_vec()
}
#[wasm_bindgen]
pub fn encrypt_symmetric(key: &[u8], message: &[u8]) -> Result<Vec<u8>, JsValue> {
symmetric::encrypt(key, message)
@@ -70,3 +121,15 @@ pub fn decrypt_symmetric(key: &[u8], ciphertext: &[u8]) -> Result<Vec<u8>, JsVal
symmetric::decrypt(key, ciphertext)
.map_err(|e| JsValue::from_str(&e.to_string()))
}
#[wasm_bindgen]
pub fn encrypt_with_password(password: &str, message: &[u8]) -> Result<Vec<u8>, JsValue> {
symmetric::encrypt_with_password(password, message)
.map_err(|e| JsValue::from_str(&e.to_string()))
}
#[wasm_bindgen]
pub fn decrypt_with_password(password: &str, ciphertext: &[u8]) -> Result<Vec<u8>, JsValue> {
symmetric::decrypt_with_password(password, ciphertext)
.map_err(|e| JsValue::from_str(&e.to_string()))
}