#![allow(unused)]
#![allow(non_snake_case)]
#![allow(non_snake_case)]
use std::sync::Arc;
use std::time::{Duration, Instant};
use async_trait::async_trait;
use tokio::sync::RwLock;
use serde::{Deserialize, Serialize};
use subtle::ConstantTimeEq;
#[cfg(not(windows))]
use pkcs11;
use crate::core::{RiResult, RiError};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum RiHSMType {
PKCS11,
TPM20,
Software,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum RiConnectionStatus {
Disconnected,
Connecting,
Connected,
Error,
Reconnecting,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum RiKeyType {
RSA { size: usize },
ECDSA { curve: RiECCurve },
EdDSA { curve: RiECCurve },
AES { size: usize },
SM4,
HMAC { size: usize },
Dilithium { level: u8 },
Falcon { level: u8 },
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum RiECCurve {
P256,
P384,
P521,
Secp256k1,
SM2,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RiKeyInfo {
pub id: String,
pub key_type: RiKeyType,
pub label: String,
pub sensitive: bool,
pub extractable: bool,
pub created_at: chrono::DateTime<chrono::Utc>,
pub last_used: Option<chrono::DateTime<chrono::Utc>>,
pub usage_count: u64,
}
#[derive(Debug, Clone)]
pub struct RiOperationResult<T> {
pub data: T,
pub duration: Duration,
pub hardware_accelerated: bool,
}
#[derive(Debug, Clone)]
pub enum RiHSMEvent {
Connected { hsm_type: RiHSMType, device_info: String },
Disconnected { hsm_type: RiHSMType, reason: String },
KeyOperation { operation: String, key_id: String, duration: Duration },
Error { error: String, recoverable: bool },
SlotChanged { slot_id: u32, present: bool },
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RiHSMConfig {
pub hsm_type: RiHSMType,
pub pkcs11_library: Option<String>,
pub slot: Option<u32>,
pub token_label: Option<String>,
pub tpm_device: Option<String>,
pub pin: Option<String>,
pub secure_pin_entry: bool,
pub connection_timeout: Duration,
pub max_retries: u32,
pub enable_key_cache: bool,
pub cache_ttl: Duration,
}
impl Default for RiHSMConfig {
fn default() -> Self {
Self {
hsm_type: RiHSMType::PKCS11,
pkcs11_library: None,
slot: None,
token_label: None,
tpm_device: None,
pin: None,
secure_pin_entry: true,
connection_timeout: Duration::from_secs(30),
max_retries: 3,
enable_key_cache: true,
cache_ttl: Duration::from_secs(300),
}
}
}
#[derive(Debug, Clone)]
pub struct RiHSMStatistics {
pub total_connections: Arc<RwLock<u64>>,
pub current_status: Arc<RwLock<RiConnectionStatus>>,
pub total_operations: Arc<RwLock<u64>>,
pub hardware_operations: Arc<RwLock<u64>>,
pub software_fallbacks: Arc<RwLock<u64>>,
pub average_latency_ms: Arc<RwLock<f64>>,
pub last_operation: Arc<RwLock<Option<Instant>>>,
pub error_count: Arc<RwLock<u64>>,
pub connected_at: Arc<RwLock<Option<Instant>>>,
}
impl RiHSMStatistics {
pub fn new() -> Self {
Self {
total_connections: Arc::new(RwLock::new(0)),
current_status: Arc::new(RwLock::new(RiConnectionStatus::Disconnected)),
total_operations: Arc::new(RwLock::new(0)),
hardware_operations: Arc::new(RwLock::new(0)),
software_fallbacks: Arc::new(RwLock::new(0)),
average_latency_ms: Arc::new(RwLock::new(0.0)),
last_operation: Arc::new(RwLock::new(None)),
error_count: Arc::new(RwLock::new(0)),
connected_at: Arc::new(RwLock::new(None)),
}
}
pub async fn record_operation(&self, hardware_accelerated: bool, duration: Duration) {
let mut total_ops = self.total_operations.write().await;
*total_ops += 1;
if hardware_accelerated {
let mut hw_ops = self.hardware_operations.write().await;
*hw_ops += 1;
} else {
let mut sw_fallbacks = self.software_fallbacks.write().await;
*sw_fallbacks += 1;
}
let mut last_op = self.last_operation.write().await;
*last_op = Some(Instant::now());
let latency_ms = duration.as_secs_f64() * 1000.0;
let mut avg_latency = self.average_latency_ms.write().await;
*avg_latency = (*avg_latency * 0.9) + (latency_ms * 0.1);
}
pub async fn record_error(&self) {
let mut errors = self.error_count.write().await;
*errors += 1;
}
pub async fn record_connection(&self, status: RiConnectionStatus) {
let mut total_conns = self.total_connections.write().await;
*total_conns += 1;
let mut current_status = self.current_status.write().await;
*current_status = status;
if status == RiConnectionStatus::Connected {
let mut connected_at = self.connected_at.write().await;
*connected_at = Some(Instant::now());
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RiDeviceInfo {
pub manufacturer: String,
pub model: String,
pub serial_number: String,
pub firmware_version: String,
pub supported_algorithms: Vec<String>,
pub hardware_version: String,
pub token_flags: Vec<String>,
}
#[async_trait]
pub trait RiHSM: Send + Sync {
async fn connect(&mut self, config: &RiHSMConfig) -> RiResult<RiDeviceInfo>;
async fn disconnect(&mut self) -> RiResult<()>;
fn is_connected(&self) -> bool;
fn hsm_type(&self) -> RiHSMType;
async fn generate_key(
&mut self,
key_type: RiKeyType,
label: Option<&str>,
) -> RiResult<String>;
async fn generate_symmetric_key(
&mut self,
key_type: RiKeyType,
label: Option<&str>,
) -> RiResult<String>;
async fn import_key(
&mut self,
key_type: RiKeyType,
key_data: &[u8],
label: Option<&str>,
extractable: bool,
) -> RiResult<String>;
async fn export_public_key(&mut self, key_id: &str) -> RiResult<Vec<u8>>;
async fn export_key(&mut self, key_id: &str) -> RiResult<Vec<u8>>;
async fn sign(
&mut self,
key_id: &str,
data: &[u8],
) -> RiResult<Vec<u8>>;
async fn verify(
&mut self,
key_id: &str,
data: &[u8],
signature: &[u8],
) -> RiResult<bool>;
async fn encrypt(
&mut self,
key_id: &str,
data: &[u8],
) -> RiResult<Vec<u8>>;
async fn decrypt(
&mut self,
key_id: &str,
ciphertext: &[u8],
) -> RiResult<Vec<u8>>;
async fn encrypt_symmetric(
&mut self,
key_id: &str,
data: &[u8],
iv: Option<&[u8]>,
) -> RiResult<Vec<u8>>;
async fn decrypt_symmetric(
&mut self,
key_id: &str,
ciphertext: &[u8],
iv: Option<&[u8]>,
) -> RiResult<Vec<u8>>;
async fn random(&mut self, size: usize) -> RiResult<Vec<u8>>;
async fn hash(&mut self, algorithm: &str, data: &[u8]) -> RiResult<Vec<u8>>;
async fn derive_key(
&mut self,
base_key_id: &str,
template: RiKeyType,
label: Option<&str>,
) -> RiResult<String>;
async fn delete_key(&mut self, key_id: &str) -> RiResult<()>;
async fn list_keys(&mut self) -> RiResult<Vec<RiKeyInfo>>;
async fn get_key_info(&mut self, key_id: &str) -> RiResult<RiKeyInfo>;
fn get_device_info(&self) -> Option<RiDeviceInfo>;
}
#[cfg(not(windows))]
pub struct RiPKCS11HSM {
config: Option<RiHSMConfig>,
connected: bool,
device_info: Option<RiDeviceInfo>,
library: Option<pkcs11::Ctx>,
session: Option<pkcs11::Session>,
slot: Option<pkcs11::Slot>,
statistics: Arc<RiHSMStatistics>,
}
#[cfg(not(windows))]
impl RiPKCS11HSM {
pub fn new() -> Self {
Self {
config: None,
connected: false,
device_info: None,
library: None,
session: None,
slot: None,
statistics: Arc::new(RiHSMStatistics::new()),
}
}
fn initialize_library(&mut self, library_path: &str) -> RiResult<()> {
let library = pkcs11::Ctx::new(library_path)
.map_err(|e| RiError::CryptoError(format!("Failed to load PKCS#11 library: {}", e)))?;
library.initialize()
.map_err(|e| RiError::CryptoError(format!("Failed to initialize PKCS#11: {}", e)))?;
self.library = Some(library);
Ok(())
}
fn get_available_slots(&self) -> RiResult<Vec<pkcs11::Slot>> {
let library = self.library.as_ref()
.ok_or_else(|| RiError::CryptoError("PKCS#11 library not loaded".to_string()))?;
let slots = library.get_slot_list(false)
.map_err(|e| RiError::CryptoError(format!("Failed to get slot list: {}", e)))?;
Ok(slots)
}
fn find_slot(&self, slot_number: Option<u32>, token_label: Option<&str>) -> RiResult<pkcs11::Slot> {
let library = self.library.as_ref()
.ok_or_else(|| RiError::CryptoError("PKCS#11 library not loaded".to_string()))?;
let slots = self.get_available_slots()?;
for slot in slots {
let token_info = library.get_token_info(slot)
.map_err(|e| RiError::CryptoError(format!("Failed to get token info: {}", e)))?;
if let Some(num) = slot_number {
if slot == num {
return Ok(slot);
}
}
if let Some(label) = token_label {
let token_label_str = String::from_utf8_lossy(&token_info.label);
if token_label_str.trim() == label {
return Ok(slot);
}
}
}
Err(RiError::CryptoError("Slot not found".to_string()))
}
fn open_session(&mut self, slot: pkcs11::Slot) -> RiResult<()> {
let library = self.library.as_ref()
.ok_or_else(|| RiError::CryptoError("PKCS#11 library not loaded".to_string()))?;
let session = library.open_session(
slot,
pkcs11::SessionType::Serial,
None,
None,
).map_err(|e| RiError::CryptoError(format!("Failed to open session: {}", e)))?;
self.session = Some(session);
self.slot = Some(slot);
Ok(())
}
fn authenticate(&mut self, pin: Option<&str>) -> RiResult<()> {
let session = self.session.as_ref()
.ok_or_else(|| RiError::CryptoError("Session not open".to_string()))?;
let pin = pin.unwrap_or("");
session.login(pkcs11::UserType::User, pin)
.map_err(|e| RiError::CryptoError(format!("Login failed: {}", e)))?;
Ok(())
}
fn find_objects(&self, template: &[pkcs11::Attribute]) -> RiResult<Vec<pkcs11::ObjectHandle>> {
let session = self.session.as_ref()
.ok_or_else(|| RiError::CryptoError("Session not open".to_string()))?;
session.find_objects_init(template)
.map_err(|e| RiError::CryptoError(format!("Find objects init failed: {}", e)))?;
let objects = session.find_objects(100)
.map_err(|e| RiError::CryptoError(format!("Find objects failed: {}", e)))?;
session.find_objects_final()
.map_err(|e| RiError::CryptoError(format!("Find objects final failed: {}", e)))?;
Ok(objects)
}
fn get_attribute_value(
&self,
object: pkcs11::ObjectHandle,
attribute: pkcs11::AttributeType,
) -> RiResult<Vec<u8>> {
let session = self.session.as_ref()
.ok_or_else(|| RiError::CryptoError("Session not open".to_string()))?;
let attributes = session.get_attribute_value(object, &[attribute])
.map_err(|e| RiError::CryptoError(format!("Get attribute failed: {}", e)))?;
if attributes.is_empty() {
return Err(RiError::CryptoError("Attribute not found".to_string()));
}
Ok(attributes[0].value().to_vec())
}
}
#[cfg(not(windows))]
#[async_trait]
impl RiHSM for RiPKCS11HSM {
async fn connect(&mut self, config: &RiHSMConfig) -> RiResult<RiDeviceInfo> {
let start = Instant::now();
self.config = Some(config.clone());
let library_path = config.pkcs11_library.as_ref()
.ok_or_else(|| RiError::CryptoError("PKCS#11 library path not configured".to_string()))?;
self.initialize_library(library_path)?;
let slot = self.find_slot(config.slot, config.token_label.as_deref())?;
self.open_session(slot)?;
if let Some(pin) = &config.pin {
self.authenticate(Some(pin))?;
} else {
self.authenticate(None)?;
}
let library = match self.library.as_ref() {
Some(l) => l,
None => return Err(RiError::Other("HSM library not initialized".to_string())),
};
let token_info = library.get_token_info(slot)
.map_err(|e| RiError::CryptoError(format!("Failed to get token info: {}", e)))?;
let device_info = RiDeviceInfo {
manufacturer: String::from_utf8_lossy(&token_info.manufacturer_id).trim().to_string(),
model: String::from_utf8_lossy(&token_info.model).trim().to_string(),
serial_number: String::from_utf8_lossy(&token_info.serial_number).trim().to_string(),
firmware_version: "N/A".to_string(),
supported_algorithms: vec!["RSA".to_string(), "ECDSA".to_string(), "AES".to_string()],
hardware_version: format!("{}.{}", token_info.hardware_version.major, token_info.hardware_version.minor),
token_flags: vec!["RNG".to_string(), "LoginRequired".to_string()],
};
self.device_info = Some(device_info.clone());
self.connected = true;
self.statistics.record_connection(RiConnectionStatus::Connected).await;
Ok(device_info)
}
async fn disconnect(&mut self) -> RiResult<()> {
if let Some(session) = &self.session {
session.logout()
.ok();
session.close_session()
.ok();
}
self.session = None;
self.slot = None;
self.connected = false;
self.statistics.record_connection(RiConnectionStatus::Disconnected).await;
Ok(())
}
fn is_connected(&self) -> bool {
self.connected
}
fn hsm_type(&self) -> RiHSMType {
RiHSMType::PKCS11
}
async fn generate_key(
&mut self,
key_type: RiKeyType,
label: Option<&str>,
) -> RiResult<String> {
let start = Instant::now();
let session = self.session.as_ref()
.ok_or_else(|| RiError::CryptoError("Session not open".to_string()))?;
let key_id = format!("{:x}", rand::random::<u64>());
let template = match key_type {
RiKeyType::RSA { size } => {
vec![
pkcs11::Attribute::Class(pkcs11::ObjectClass::PUBLIC_KEY),
pkcs11::Attribute::KeyType(pkcs11::KeyType::RSA),
pkcs11::Attribute::Token(true),
pkcs11::Attribute::Sensitive(true),
pkcs11::Attribute::Extractable(false),
pkcs11::Attribute::ModulusBits(size as u64),
pkcs11::Attribute::PublicExponent(vec![0x01, 0x00, 0x01]),
pkcs11::Attribute::Label(label.unwrap_or("RSA Key").as_bytes().to_vec()),
]
}
RiKeyType::ECDSA { curve } => {
let curve_oid = match curve {
RiECCurve::P256 => vec![0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07],
RiECCurve::P384 => vec![0x06, 0x05, 0x2B, 0x81, 0x04, 0x00, 0x22],
RiECCurve::P521 => vec![0x06, 0x05, 0x2B, 0x81, 0x04, 0x00, 0x23],
RiECCurve::Secp256k1 => vec![0x06, 0x05, 0x2B, 0x81, 0x04, 0x00, 0x0A],
RiECCurve::SM2 => vec![0x06, 0x08, 0x2A, 0x81, 0x1C, 0xCF, 0x55, 0x01, 0x82, 0x2D],
_ => vec![0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07],
};
vec![
pkcs11::Attribute::Class(pkcs11::ObjectClass::PUBLIC_KEY),
pkcs11::Attribute::KeyType(pkcs11::KeyType::EC),
pkcs11::Attribute::Token(true),
pkcs11::Attribute::Sensitive(true),
pkcs11::Attribute::Extractable(false),
pkcs11::Attribute::EcdsaParams(curve_oid),
pkcs11::Attribute::Label(label.unwrap_or("EC Key").as_bytes().to_vec()),
]
}
_ => {
return Err(RiError::CryptoError("Unsupported key type for asymmetric key generation".to_string()));
}
};
session.generate_key_pair(&template, &[])
.map_err(|e| RiError::CryptoError(format!("Failed to generate key pair: {}", e)))?;
self.statistics.record_operation(true, start.elapsed()).await;
Ok(key_id)
}
async fn generate_symmetric_key(
&mut self,
key_type: RiKeyType,
label: Option<&str>,
) -> RiResult<String> {
let start = Instant::now();
let session = self.session.as_ref()
.ok_or_else(|| RiError::CryptoError("Session not open".to_string()))?;
let key_id = format!("{:x}", rand::random::<u64>());
let (key_size, key_type_pkcs11) = match key_type {
RiKeyType::AES { size } => (size, pkcs11::KeyType::AES),
RiKeyType::SM4 => (128, pkcs11::KeyType::AES),
RiKeyType::HMAC { size } => (size, pkcs11::KeyType::GENERIC_SECRET),
_ => {
return Err(RiError::CryptoError("Unsupported key type for symmetric key generation".to_string()));
}
};
let template = vec![
pkcs11::Attribute::Class(pkcs11::ObjectClass::SECRET_KEY),
pkcs11::Attribute::KeyType(key_type_pkcs11),
pkcs11::Attribute::Token(true),
pkcs11::Attribute::Sensitive(true),
pkcs11::Attribute::Extractable(false),
pkcs11::Attribute::ValueLen(key_size as u64),
pkcs11::Attribute::Label(label.unwrap_or("Symmetric Key").as_bytes().to_vec()),
];
session.generate_key(&template, None, None)
.map_err(|e| RiError::CryptoError(format!("Failed to generate symmetric key: {}", e)))?;
self.statistics.record_operation(true, start.elapsed()).await;
Ok(key_id)
}
async fn import_key(
&mut self,
key_type: RiKeyType,
key_data: &[u8],
label: Option<&str>,
extractable: bool,
) -> RiResult<String> {
let start = Instant::now();
let session = self.session.as_ref()
.ok_or_else(|| RiError::CryptoError("Session not open".to_string()))?;
let key_id = format!("{:x}", rand::random::<u64>());
let template = match key_type {
RiKeyType::RSA { .. } => {
vec![
pkcs11::Attribute::Class(pkcs11::ObjectClass::PRIVATE_KEY),
pkcs11::Attribute::KeyType(pkcs11::KeyType::RSA),
pkcs11::Attribute::Token(true),
pkcs11::Attribute::Sensitive(true),
pkcs11::Attribute::Extractable(extractable),
pkcs11::Attribute::Value(key_data.to_vec()),
pkcs11::Attribute::Label(label.unwrap_or("Imported RSA Key").as_bytes().to_vec()),
]
}
RiKeyType::ECDSA { .. } => {
vec![
pkcs11::Attribute::Class(pkcs11::ObjectClass::PRIVATE_KEY),
pkcs11::Attribute::KeyType(pkcs11::KeyType::EC),
pkcs11::Attribute::Token(true),
pkcs11::Attribute::Sensitive(true),
pkcs11::Attribute::Extractable(extractable),
pkcs11::Attribute::Value(key_data.to_vec()),
pkcs11::Attribute::Label(label.unwrap_or("Imported EC Key").as_bytes().to_vec()),
]
}
RiKeyType::AES { size } => {
vec![
pkcs11::Attribute::Class(pkcs11::ObjectClass::SECRET_KEY),
pkcs11::Attribute::KeyType(pkcs11::KeyType::AES),
pkcs11::Attribute::Token(true),
pkcs11::Attribute::Sensitive(true),
pkcs11::Attribute::Extractable(extractable),
pkcs11::Attribute::Value(key_data.to_vec()),
pkcs11::Attribute::ValueLen(size as u64),
pkcs11::Attribute::Label(label.unwrap_or("Imported AES Key").as_bytes().to_vec()),
]
}
_ => {
return Err(RiError::CryptoError("Unsupported key type for import".to_string()));
}
};
session.create_object(&template)
.map_err(|e| RiError::CryptoError(format!("Failed to import key: {}", e)))?;
self.statistics.record_operation(true, start.elapsed()).await;
Ok(key_id)
}
async fn export_public_key(&mut self, key_id: &str) -> RiResult<Vec<u8>> {
let start = Instant::now();
let template = vec![
pkcs11::Attribute::Label(key_id.as_bytes().to_vec()),
];
let objects = self.find_objects(&template)?;
if objects.is_empty() {
return Err(RiError::CryptoError("Key not found".to_string()));
}
let public_key = self.get_attribute_value(objects[0], pkcs11::Attribute::PublicExponent)?;
self.statistics.record_operation(true, start.elapsed()).await;
Ok(public_key)
}
async fn export_key(&mut self, key_id: &str) -> RiResult<Vec<u8>> {
let start = Instant::now();
let template = vec![
pkcs11::Attribute::Label(key_id.as_bytes().to_vec()),
];
let objects = self.find_objects(&template)?;
if objects.is_empty() {
return Err(RiError::CryptoError("Key not found".to_string()));
}
let key_data = self.get_attribute_value(objects[0], pkcs11::Attribute::Value)?;
self.statistics.record_operation(true, start.elapsed()).await;
Ok(key_data)
}
async fn sign(&mut self, key_id: &str, data: &[u8]) -> RiResult<Vec<u8>> {
let start = Instant::now();
let session = self.session.as_ref()
.ok_or_else(|| RiError::CryptoError("Session not open".to_string()))?;
let template = vec![
pkcs11::Attribute::Label(key_id.as_bytes().to_vec()),
];
let objects = self.find_objects(&template)?;
if objects.is_empty() {
return Err(RiError::CryptoError("Key not found".to_string()));
}
let signature = session.sign(
pkcs11::Mechanism::Ecdsa1,
objects[0],
data,
).map_err(|e| RiError::CryptoError(format!("Signing failed: {}", e)))?;
self.statistics.record_operation(true, start.elapsed()).await;
Ok(signature)
}
async fn verify(&mut self, key_id: &str, data: &[u8], signature: &[u8]) -> RiResult<bool> {
let start = Instant::now();
let session = self.session.as_ref()
.ok_or_else(|| RiError::CryptoError("Session not open".to_string()))?;
let template = vec![
pkcs11::Attribute::Label(key_id.as_bytes().to_vec()),
];
let objects = self.find_objects(&template)?;
if objects.is_empty() {
return Err(RiError::CryptoError("Key not found".to_string()));
}
let result = session.verify(
pkcs11::Mechanism::Ecdsa1,
objects[0],
data,
signature,
).map_err(|e| RiError::CryptoError(format!("Verification failed: {}", e)))?;
self.statistics.record_operation(true, start.elapsed()).await;
Ok(result)
}
async fn encrypt(&mut self, key_id: &str, data: &[u8]) -> RiResult<Vec<u8>> {
let start = Instant::now();
let session = self.session.as_ref()
.ok_or_else(|| RiError::CryptoError("Session not open".to_string()))?;
let template = vec![
pkcs11::Attribute::Label(key_id.as_bytes().to_vec()),
];
let objects = self.find_objects(&template)?;
if objects.is_empty() {
return Err(RiError::CryptoError("Key not found".to_string()));
}
let ciphertext = session.encrypt(
pkcs11::Mechanism::RsaPkcs1,
objects[0],
data,
).map_err(|e| RiError::CryptoError(format!("Encryption failed: {}", e)))?;
self.statistics.record_operation(true, start.elapsed()).await;
Ok(ciphertext)
}
async fn decrypt(&mut self, key_id: &str, ciphertext: &[u8]) -> RiResult<Vec<u8>> {
let start = Instant::now();
let session = self.session.as_ref()
.ok_or_else(|| RiError::CryptoError("Session not open".to_string()))?;
let template = vec![
pkcs11::Attribute::Label(key_id.as_bytes().to_vec()),
];
let objects = self.find_objects(&template)?;
if objects.is_empty() {
return Err(RiError::CryptoError("Key not found".to_string()));
}
let plaintext = session.decrypt(
pkcs11::Mechanism::RsaPkcs1,
objects[0],
ciphertext,
).map_err(|e| RiError::CryptoError(format!("Decryption failed: {}", e)))?;
self.statistics.record_operation(true, start.elapsed()).await;
Ok(plaintext)
}
async fn encrypt_symmetric(
&mut self,
key_id: &str,
data: &[u8],
iv: Option<&[u8]>,
) -> RiResult<Vec<u8>> {
let start = Instant::now();
let iv = iv.ok_or_else(|| {
RiError::CryptoError("IV (Initialization Vector) is required for symmetric encryption. Provide a unique random IV for each encryption operation.".to_string())
})?;
if iv.len() != 16 {
return Err(RiError::CryptoError(
format!("Invalid IV length: expected 16 bytes, got {}. IV must be exactly 16 bytes for AES-CBC mode.", iv.len())
));
}
let session = self.session.as_ref()
.ok_or_else(|| RiError::CryptoError("Session not open".to_string()))?;
let template = vec![
pkcs11::Attribute::Label(key_id.as_bytes().to_vec()),
];
let objects = self.find_objects(&template)?;
if objects.is_empty() {
return Err(RiError::CryptoError("Key not found".to_string()));
}
let mechanism = pkcs11::Mechanism::CbcPkcs5(iv.to_vec());
let ciphertext = session.encrypt(
mechanism,
objects[0],
data,
).map_err(|e| RiError::CryptoError(format!("Symmetric encryption failed: {}", e)))?;
self.statistics.record_operation(true, start.elapsed()).await;
Ok(ciphertext)
}
async fn decrypt_symmetric(
&mut self,
key_id: &str,
ciphertext: &[u8],
iv: Option<&[u8]>,
) -> RiResult<Vec<u8>> {
let start = Instant::now();
let iv = iv.ok_or_else(|| {
RiError::CryptoError("IV (Initialization Vector) is required for symmetric decryption. Provide the same IV that was used for encryption.".to_string())
})?;
if iv.len() != 16 {
return Err(RiError::CryptoError(
format!("Invalid IV length: expected 16 bytes, got {}. IV must be exactly 16 bytes for AES-CBC mode.", iv.len())
));
}
let session = self.session.as_ref()
.ok_or_else(|| RiError::CryptoError("Session not open".to_string()))?;
let template = vec![
pkcs11::Attribute::Label(key_id.as_bytes().to_vec()),
];
let objects = self.find_objects(&template)?;
if objects.is_empty() {
return Err(RiError::CryptoError("Key not found".to_string()));
}
let mechanism = pkcs11::Mechanism::CbcPkcs5(iv.to_vec());
let plaintext = session.decrypt(
mechanism,
objects[0],
ciphertext,
).map_err(|e| RiError::CryptoError(format!("Symmetric decryption failed: {}", e)))?;
self.statistics.record_operation(true, start.elapsed()).await;
Ok(plaintext)
}
async fn random(&mut self, size: usize) -> RiResult<Vec<u8>> {
let start = Instant::now();
let session = self.session.as_ref()
.ok_or_else(|| RiError::CryptoError("Session not open".to_string()))?;
let random = session.generate_random(size)
.map_err(|e| RiError::CryptoError(format!("Random generation failed: {}", e)))?;
self.statistics.record_operation(true, start.elapsed()).await;
Ok(random)
}
async fn hash(&mut self, algorithm: &str, data: &[u8]) -> RiResult<Vec<u8>> {
let start = Instant::now();
let session = self.session.as_ref()
.ok_or_else(|| RiError::CryptoError("Session not open".to_string()))?;
let mechanism = match algorithm.to_uppercase().as_str() {
"SHA-256" | "SHA256" => pkcs11::Mechanism::Sha256,
"SHA-384" | "SHA384" => pkcs11::Mechanism::Sha384,
"SHA-512" | "SHA512" => pkcs11::Mechanism::Sha512,
"SM3" => pkcs11::Mechanism::Sha256,
_ => return Err(RiError::CryptoError("Unsupported hash algorithm".to_string())),
};
let hash_data = session.hash(mechanism, data)
.map_err(|e| RiError::CryptoError(format!("Hashing failed: {}", e)))?;
self.statistics.record_operation(true, start.elapsed()).await;
Ok(hash_data)
}
async fn derive_key(
&mut self,
base_key_id: &str,
template: RiKeyType,
label: Option<&str>,
) -> RiResult<String> {
Err(RiError::CryptoError("Key derivation not yet implemented for PKCS#11".to_string()))
}
async fn delete_key(&mut self, key_id: &str) -> RiResult<()> {
let start = Instant::now();
let session = self.session.as_ref()
.ok_or_else(|| RiError::CryptoError("Session not open".to_string()))?;
let template = vec![
pkcs11::Attribute::Label(key_id.as_bytes().to_vec()),
];
let objects = self.find_objects(&template)?;
for object in objects {
session.destroy_object(object)
.map_err(|e| RiError::CryptoError(format!("Failed to delete key: {}", e)))?;
}
self.statistics.record_operation(true, start.elapsed()).await;
Ok(())
}
async fn list_keys(&mut self) -> RiResult<Vec<RiKeyInfo>> {
let start = Instant::now();
let session = self.session.as_ref()
.ok_or_else(|| RiError::CryptoError("Session not open".to_string()))?;
let template = vec![
pkcs11::Attribute::Token(true),
];
let objects = self.find_objects(&template)?;
let mut keys = Vec::with_capacity(4);
for object in objects {
let label = self.get_attribute_value(object, pkcs11::Attribute::Label)?;
let key_type = self.get_attribute_value(object, pkcs11::Attribute::KeyType)?;
let label_str = String::from_utf8_lossy(&label).to_string();
let key_type_val = if key_type.len() >= 4 {
u32::from_be_bytes([key_type[0], key_type[1], key_type[2], key_type[3]]) as u64
} else {
0
};
let ri_key_type = match key_type_val {
_ => RiKeyType::RSA { size: 2048 },
};
let key_info = RiKeyInfo {
id: label_str.clone(),
key_type: ri_key_type,
label: label_str,
sensitive: true,
extractable: false,
created_at: chrono::Utc::now(),
last_used: None,
usage_count: 0,
};
keys.push(key_info);
}
self.statistics.record_operation(true, start.elapsed()).await;
Ok(keys)
}
async fn get_key_info(&mut self, key_id: &str) -> RiResult<RiKeyInfo> {
let template = vec![
pkcs11::Attribute::Label(key_id.as_bytes().to_vec()),
];
let objects = self.find_objects(&template)?;
if objects.is_empty() {
return Err(RiError::CryptoError("Key not found".to_string()));
}
let label = self.get_attribute_value(objects[0], pkcs11::Attribute::Label)?;
let label_str = String::from_utf8_lossy(&label).to_string();
Ok(RiKeyInfo {
id: key_id.to_string(),
key_type: RiKeyType::RSA { size: 2048 },
label: label_str,
sensitive: true,
extractable: false,
created_at: chrono::Utc::now(),
last_used: None,
usage_count: 0,
})
}
fn get_device_info(&self) -> Option<RiDeviceInfo> {
self.device_info.clone()
}
}
pub struct RiHSMManager {
active_hsm: Option<Box<dyn RiHSM>>,
hsm_type: RiHSMType,
config: Option<RiHSMConfig>,
statistics: Arc<RiHSMStatistics>,
event_callback: Option<Arc<dyn Fn(RiHSMEvent) + Send + Sync>>,
}
impl RiHSMManager {
pub fn new() -> Self {
Self {
active_hsm: None,
hsm_type: RiHSMType::PKCS11,
config: None,
statistics: Arc::new(RiHSMStatistics::new()),
event_callback: None,
}
}
pub fn set_event_callback<F>(&mut self, callback: F)
where
F: Fn(RiHSMEvent) + Send + Sync + 'static,
{
self.event_callback = Some(Arc::new(callback));
}
fn emit_event(&self, event: RiHSMEvent) {
if let Some(callback) = &self.event_callback {
callback(event);
}
}
pub async fn connect_pkcs11(&mut self, library_path: &str) -> RiResult<RiDeviceInfo> {
let mut config = RiHSMConfig {
hsm_type: RiHSMType::PKCS11,
pkcs11_library: Some(library_path.to_string()),
..Default::default()
};
self.connect_with_config(&config).await
}
pub async fn connect_with_config(&mut self, config: &RiHSMConfig) -> RiResult<RiDeviceInfo> {
self.config = Some(config.clone());
#[cfg(not(windows))]
let hsm: Box<dyn RiHSM> = match config.hsm_type {
RiHSMType::PKCS11 => Box::new(RiPKCS11HSM::new()),
RiHSMType::TPM20 => {
return Err(RiError::CryptoError(
"TPM 2.0 is not yet supported. Please use PKCS#11 devices.".to_string()
));
}
RiHSMType::Software => Box::new(RiPKCS11HSM::new()),
};
#[cfg(windows)]
let hsm: Box<dyn RiHSM> = match config.hsm_type {
RiHSMType::PKCS11 | RiHSMType::Software => {
return Err(RiError::CryptoError(
"PKCS#11 is not supported on Windows. HSM features require a Unix-like operating system.".to_string()
));
}
RiHSMType::TPM20 => {
return Err(RiError::CryptoError(
"TPM 2.0 is not yet supported. Please use PKCS#11 devices on Unix systems.".to_string()
));
}
};
let device_info = hsm.connect(config).await?;
self.active_hsm = Some(hsm);
self.hsm_type = config.hsm_type;
self.emit_event(RiHSMEvent::Connected {
hsm_type: config.hsm_type,
device_info: format!("{} - {}", device_info.manufacturer, device_info.model),
});
Ok(device_info)
}
pub async fn disconnect(&mut self) -> RiResult<()> {
if let Some(mut hsm) = self.active_hsm.take() {
hsm.disconnect().await?;
self.emit_event(RiHSMEvent::Disconnected {
hsm_type: self.hsm_type,
reason: "User requested".to_string(),
});
}
Ok(())
}
pub fn is_connected(&self) -> bool {
self.active_hsm.as_ref().map(|h| h.is_connected()).unwrap_or(false)
}
pub fn hsm_type(&self) -> RiHSMType {
self.hsm_type
}
pub async fn generate_key(
&mut self,
key_type: RiKeyType,
label: Option<&str>,
) -> RiResult<String> {
let hsm = self.active_hsm.as_mut()
.ok_or_else(|| RiError::CryptoError("No HSM connected".to_string()))?;
let key_id = hsm.generate_key(key_type, label).await?;
self.emit_event(RiHSMEvent::KeyOperation {
operation: "generate_key".to_string(),
key_id: key_id.clone(),
duration: Duration::from_millis(100),
});
Ok(key_id)
}
pub async fn generate_symmetric_key(
&mut self,
key_type: RiKeyType,
label: Option<&str>,
) -> RiResult<String> {
let hsm = self.active_hsm.as_mut()
.ok_or_else(|| RiError::CryptoError("No HSM connected".to_string()))?;
hsm.generate_symmetric_key(key_type, label).await
}
pub async fn import_key(
&mut self,
key_type: RiKeyType,
key_data: &[u8],
label: Option<&str>,
extractable: bool,
) -> RiResult<String> {
let hsm = self.active_hsm.as_mut()
.ok_or_else(|| RiError::CryptoError("No HSM connected".to_string()))?;
hsm.import_key(key_type, key_data, label, extractable).await
}
pub async fn sign(&mut self, key_id: &str, data: &[u8]) -> RiResult<Vec<u8>> {
let hsm = self.active_hsm.as_mut()
.ok_or_else(|| RiError::CryptoError("No HSM connected".to_string()))?;
let start = Instant::now();
let signature = hsm.sign(key_id, data).await?;
self.emit_event(RiHSMEvent::KeyOperation {
operation: "sign".to_string(),
key_id: key_id.to_string(),
duration: start.elapsed(),
});
Ok(signature)
}
pub async fn verify(&mut self, key_id: &str, data: &[u8], signature: &[u8]) -> RiResult<bool> {
let hsm = self.active_hsm.as_mut()
.ok_or_else(|| RiError::CryptoError("No HSM connected".to_string()))?;
hsm.verify(key_id, data, signature).await
}
pub async fn encrypt(&mut self, key_id: &str, data: &[u8]) -> RiResult<Vec<u8>> {
let hsm = self.active_hsm.as_mut()
.ok_or_else(|| RiError::CryptoError("No HSM connected".to_string()))?;
hsm.encrypt(key_id, data).await
}
pub async fn decrypt(&mut self, key_id: &str, ciphertext: &[u8]) -> RiResult<Vec<u8>> {
let hsm = self.active_hsm.as_mut()
.ok_or_else(|| RiError::CryptoError("No HSM connected".to_string()))?;
hsm.decrypt(key_id, ciphertext).await
}
pub async fn random(&mut self, size: usize) -> RiResult<Vec<u8>> {
let hsm = self.active_hsm.as_mut()
.ok_or_else(|| RiError::CryptoError("No HSM connected".to_string()))?;
hsm.random(size).await
}
pub async fn hash(&mut self, algorithm: &str, data: &[u8]) -> RiResult<Vec<u8>> {
let hsm = self.active_hsm.as_mut()
.ok_or_else(|| RiError::CryptoError("No HSM connected".to_string()))?;
hsm.hash(algorithm, data).await
}
pub async fn delete_key(&mut self, key_id: &str) -> RiResult<()> {
let hsm = self.active_hsm.as_mut()
.ok_or_else(|| RiError::CryptoError("No HSM connected".to_string()))?;
hsm.delete_key(key_id).await
}
pub async fn list_keys(&mut self) -> RiResult<Vec<RiKeyInfo>> {
let hsm = self.active_hsm.as_mut()
.ok_or_else(|| RiError::CryptoError("No HSM connected".to_string()))?;
hsm.list_keys().await
}
pub fn statistics(&self) -> &Arc<RiHSMStatistics> {
&self.statistics
}
pub fn device_info(&self) -> Option<RiDeviceInfo> {
self.active_hsm.as_ref().and_then(|h| h.get_device_info())
}
}
impl Default for RiHSMManager {
fn default() -> Self {
Self::new()
}
}