use std::collections::HashMap;
use async_trait::async_trait;
use base64::Engine;
use bitcoin::secp256k1::{PublicKey, Secp256k1, SecretKey};
use bitcoin::{psbt::Psbt, Address, CompressedPublicKey, Network};
use chrono::Utc;
use rand::prelude::*;
use rand::rngs::OsRng;
use sha2::{Digest, Sha256};
use std::str::FromStr;
use std::time::Duration;
use tokio::sync::Mutex;
use tokio::time::sleep;
use uuid::Uuid;
use crate::security::hsm::config::SimulatorConfig;
use crate::security::hsm::error::HsmError;
use crate::security::hsm::provider::{
HsmOperation, HsmProvider, HsmProviderStatus, HsmRequest, HsmResponse, KeyGenParams, KeyInfo,
KeyPair, KeyType, KeyUsage, SigningAlgorithm,
};
#[derive(Debug)]
pub struct SimulatorHsmProvider {
config: SimulatorConfig,
keys: Mutex<HashMap<String, KeyInfo>>,
key_data: Mutex<HashMap<String, Vec<u8>>>,
rng: Mutex<OsRng>,
network: Network,
secp: Secp256k1<bitcoin::secp256k1::All>,
state: Mutex<HardwareState>,
}
#[derive(Debug, Clone)]
struct HardwareState {
battery_level: u8,
firmware_version: String,
is_locked: bool,
pin_attempts: u8,
max_pin_attempts: u8,
session_timeout: Duration,
last_operation: Option<chrono::DateTime<chrono::Utc>>,
}
impl SimulatorHsmProvider {
pub fn new(config: &SimulatorConfig) -> Result<Self, HsmError> {
std::fs::create_dir_all(&config.storage_path).map_err(|e| {
HsmError::InitializationError(format!("Failed to create storage path: {}", e))
})?;
Ok(Self {
config: config.clone(),
keys: Mutex::new(HashMap::new()),
key_data: Mutex::new(HashMap::new()),
rng: Mutex::new(OsRng),
network: Network::Testnet, secp: Secp256k1::new(),
state: Mutex::new(HardwareState {
battery_level: 100,
firmware_version: "1.0.0".to_string(),
is_locked: true,
pin_attempts: 0,
max_pin_attempts: 3,
session_timeout: Duration::from_secs(300), last_operation: None,
}),
})
}
fn generate_key_id(&self) -> String {
Uuid::new_v4().to_string()
}
async fn simulate_conditions(&self) -> Result<(), HsmError> {
let mut state = self.state.lock().await;
if let Some(last_op) = state.last_operation {
let now = Utc::now();
let elapsed = now.signed_duration_since(last_op);
if elapsed.to_std().unwrap_or_default() > state.session_timeout {
state.is_locked = true;
return Err(HsmError::AuthenticationError(
"Session timed out".to_string(),
));
}
}
state.last_operation = Some(Utc::now());
if state.is_locked {
return Err(HsmError::DeviceLocked("Device is locked".to_string()));
}
if state.battery_level > 0 {
state.battery_level = state.battery_level.saturating_sub(1);
} else {
return Err(HsmError::HardwareFailure("Battery depleted".to_string()));
}
drop(state);
if self.config.simulate_latency {
sleep(Duration::from_millis(self.config.latency_ms)).await;
}
if self.config.simulate_failures {
let mut rng = self.rng.lock().await;
let failure_roll: f64 = rng.gen();
if failure_roll < self.config.failure_rate {
return Err(HsmError::HardwareFailure(
"Random hardware failure".to_string(),
));
}
}
Ok(())
}
pub async fn unlock(&self, pin: &str) -> Result<(), HsmError> {
let mut state = self.state.lock().await;
const CORRECT_PIN: &str = "1234";
if state.pin_attempts >= state.max_pin_attempts {
return Err(HsmError::PinLocked(
"Too many incorrect attempts, device is locked".to_string(),
));
}
if pin != CORRECT_PIN {
state.pin_attempts += 1;
return Err(HsmError::AuthenticationError(format!(
"Incorrect PIN, {} attempts remaining",
state.max_pin_attempts - state.pin_attempts
)));
}
state.is_locked = false;
state.pin_attempts = 0;
state.last_operation = Some(chrono::Utc::now());
Ok(())
}
async fn generate_bitcoin_key(
&self,
_params: &KeyGenParams,
) -> Result<(Vec<u8>, Vec<u8>), HsmError> {
self.simulate_conditions().await?;
let mut rng = self.rng.lock().await;
let secret_key = SecretKey::new(&mut *rng);
let public_key = PublicKey::from_secret_key(&self.secp, &secret_key);
let compressed_key = CompressedPublicKey::from_slice(&public_key.serialize()).unwrap();
let address = Address::p2wpkh(&compressed_key, self.network);
tracing::info!("Generated new testnet address: {}", address);
Ok((
public_key.serialize().to_vec(),
secret_key.secret_bytes().to_vec(),
))
}
async fn sign_bitcoin_transaction(&self, key_id: &str, tx: &mut Psbt) -> Result<(), HsmError> {
self.simulate_conditions().await?;
let key_data = self.key_data.lock().await;
let secret_data = key_data
.get(key_id)
.ok_or_else(|| HsmError::KeyNotFound(key_id.to_string()))?;
let secret_key = SecretKey::from_slice(secret_data)
.map_err(|e| HsmError::SigningError(format!("Invalid key data: {}", e)))?;
let public_key = PublicKey::from_secret_key(&self.secp, &secret_key);
let mut signing_keys = std::collections::BTreeMap::new();
let bitcoin_public_key = bitcoin::PublicKey::new(public_key);
signing_keys.insert(
bitcoin_public_key,
bitcoin::PrivateKey::new(secret_key, self.network),
);
let result = tx.sign(&signing_keys, &self.secp);
match result {
Ok(_) => {
tracing::info!("Successfully signed testnet transaction");
Ok(())
}
Err((_, errors)) => {
tracing::error!("Failed to sign transaction: {:?}", errors);
Err(HsmError::SigningError(
"Failed to sign transaction".to_string(),
))
}
}
}
pub async fn get_diagnostics(&self) -> Result<DeviceDiagnostics, HsmError> {
let state = self.state.lock().await;
let diagnostics = DeviceDiagnostics {
battery_level: state.battery_level,
firmware_version: state.firmware_version.clone(),
is_locked: state.is_locked,
last_operation: state.last_operation,
active_keys: self.keys.lock().await.len(),
network: "testnet".to_string(),
};
Ok(diagnostics)
}
}
#[derive(Debug, Clone, serde::Serialize)]
pub struct DeviceDiagnostics {
battery_level: u8,
firmware_version: String,
is_locked: bool,
last_operation: Option<chrono::DateTime<chrono::Utc>>,
active_keys: usize,
network: String,
}
#[async_trait]
impl HsmProvider for SimulatorHsmProvider {
async fn initialize(&self) -> Result<(), HsmError> {
std::fs::create_dir_all(&self.config.storage_path).map_err(|e| {
HsmError::InitializationError(format!("Failed to create storage path: {}", e))
})?;
tracing::info!("Initialized simulator HSM for Bitcoin testnet operations");
Ok(())
}
async fn generate_key(&self, params: KeyGenParams) -> Result<(KeyPair, KeyInfo), HsmError> {
self.simulate_conditions().await?;
let key_id = params.id.clone().unwrap_or_else(|| self.generate_key_id());
let (public_key, private_key) = match ¶ms.key_type {
KeyType::Ec { curve }
if *curve == crate::security::hsm::provider::EcCurve::Secp256k1 =>
{
self.generate_bitcoin_key(¶ms).await?
}
_ => return Err(HsmError::UnsupportedKeyType),
};
let key_info = KeyInfo {
id: key_id.clone(),
label: params.label.clone(),
key_type: params.key_type.clone(),
extractable: params.extractable,
usages: params.usages.clone(),
created_at: Utc::now(),
expires_at: params.expires_at,
attributes: params.attributes.clone(),
};
let mut keys = self.keys.lock().await;
let mut key_data = self.key_data.lock().await;
keys.insert(key_id.clone(), key_info.clone());
key_data.insert(key_id.clone(), private_key);
let key_pair = KeyPair {
id: key_id.clone(),
key_type: params.key_type,
public_key,
private_key_handle: key_id.clone(),
};
Ok((key_pair, key_info))
}
async fn sign(
&self,
key_id: &str,
algorithm: SigningAlgorithm,
data: &[u8],
) -> Result<Vec<u8>, HsmError> {
self.simulate_conditions().await?;
let keys = self.keys.lock().await;
let key_info = keys
.get(key_id)
.ok_or_else(|| HsmError::KeyNotFound(key_id.to_string()))?;
if !key_info.usages.contains(&KeyUsage::Sign) {
return Err(HsmError::PermissionDenied(
"Key does not have signing permission".to_string(),
));
}
let key_data = self.key_data.lock().await;
let private_key_data = key_data
.get(key_id)
.ok_or_else(|| HsmError::KeyNotFound(key_id.to_string()))?;
match algorithm {
SigningAlgorithm::EcdsaSha256 => {
let secret_key = SecretKey::from_slice(private_key_data)
.map_err(|e| HsmError::SigningError(format!("Invalid key data: {}", e)))?;
let mut hasher = Sha256::new();
hasher.update(data);
let message_hash = hasher.finalize();
let message = bitcoin::secp256k1::Message::from_digest_slice(&message_hash)
.map_err(|e| HsmError::SigningError(format!("Invalid message hash: {}", e)))?;
let signature = self.secp.sign_ecdsa(&message, &secret_key);
Ok(signature.serialize_der().to_vec())
}
_ => Err(HsmError::UnsupportedOperation(format!(
"Unsupported signing algorithm: {:?}",
algorithm
))),
}
}
async fn verify(
&self,
key_id: &str,
algorithm: SigningAlgorithm,
data: &[u8],
signature: &[u8],
) -> Result<bool, HsmError> {
self.simulate_conditions().await?;
let keys = self.keys.lock().await;
let key_info = keys
.get(key_id)
.ok_or_else(|| HsmError::KeyNotFound(key_id.to_string()))?;
if !key_info.usages.contains(&KeyUsage::Verify) {
return Err(HsmError::PermissionDenied(
"Key does not have verify permission".to_string(),
));
}
match algorithm {
SigningAlgorithm::EcdsaSha256 => {
match key_info.key_type {
KeyType::Ec { curve }
if curve == crate::security::hsm::provider::EcCurve::Secp256k1 =>
{
let mut hasher = Sha256::new();
hasher.update(data);
let message_hash = hasher.finalize();
let pubkey_bytes = self.export_public_key(key_id).await?;
let public_key = PublicKey::from_slice(&pubkey_bytes).map_err(|e| {
HsmError::VerificationError(format!("Invalid public key data: {}", e))
})?;
let sig = bitcoin::secp256k1::ecdsa::Signature::from_der(signature)
.map_err(|e| {
HsmError::VerificationError(format!(
"Invalid signature format: {}",
e
))
})?;
let message = bitcoin::secp256k1::Message::from_digest_slice(&message_hash)
.map_err(|e| {
HsmError::VerificationError(format!("Invalid message hash: {}", e))
})?;
match self.secp.verify_ecdsa(&message, &sig, &public_key) {
Ok(_) => Ok(true),
Err(_) => Ok(false),
}
}
_ => Err(HsmError::UnsupportedKeyType),
}
}
_ => Err(HsmError::UnsupportedOperation(format!(
"Unsupported verification algorithm: {:?}",
algorithm
))),
}
}
async fn export_public_key(&self, key_id: &str) -> Result<Vec<u8>, HsmError> {
self.simulate_conditions().await?;
let keys = self.keys.lock().await;
let key_info = keys
.get(key_id)
.ok_or_else(|| HsmError::KeyNotFound(key_id.to_string()))?;
let key_data = self.key_data.lock().await;
let private_key_data = key_data
.get(key_id)
.ok_or_else(|| HsmError::KeyNotFound(key_id.to_string()))?;
match key_info.key_type {
KeyType::Ec { curve }
if curve == crate::security::hsm::provider::EcCurve::Secp256k1 =>
{
let secret_key = SecretKey::from_slice(private_key_data).map_err(|e| {
HsmError::KeyGenerationError(format!("Invalid key data: {}", e))
})?;
let public_key = PublicKey::from_secret_key(&self.secp, &secret_key);
Ok(public_key.serialize().to_vec())
}
_ => Err(HsmError::UnsupportedKeyType),
}
}
async fn list_keys(&self) -> Result<Vec<KeyInfo>, HsmError> {
self.simulate_conditions().await?;
let keys = self.keys.lock().await;
Ok(keys.values().cloned().collect())
}
async fn delete_key(&self, key_id: &str) -> Result<(), HsmError> {
self.simulate_conditions().await?;
let mut keys = self.keys.lock().await;
let mut key_data = self.key_data.lock().await;
if keys.remove(key_id).is_none() {
return Err(HsmError::KeyNotFound(key_id.to_string()));
}
key_data.remove(key_id);
Ok(())
}
async fn get_status(&self) -> Result<HsmProviderStatus, HsmError> {
let state = self.state.lock().await;
if state.battery_level == 0 {
return Ok(HsmProviderStatus::Error("Battery depleted".to_string()));
}
if state.is_locked {
return Ok(HsmProviderStatus::Unavailable);
}
Ok(HsmProviderStatus::Ready)
}
async fn close(&self) -> Result<(), HsmError> {
let mut state = self.state.lock().await;
state.is_locked = true;
Ok(())
}
async fn execute_operation(&self, request: HsmRequest) -> Result<HsmResponse, HsmError> {
match request.operation {
HsmOperation::GenerateKey => {
let params: KeyGenParams = serde_json::from_value(request.parameters.clone())
.map_err(|e| {
HsmError::InvalidParameters(format!(
"Invalid key generation parameters: {}",
e
))
})?;
let key_pair = self.generate_key(params).await?;
let response_data = serde_json::to_value(key_pair)
.map_err(|e| HsmError::SerializationError(e.to_string()))?;
Ok(HsmResponse::success(request.id, Some(response_data)))
}
HsmOperation::Sign => {
let params: SignParams = serde_json::from_value(request.parameters.clone())
.map_err(|e| {
HsmError::InvalidParameters(format!("Invalid signing parameters: {}", e))
})?;
let signature = self
.sign(¶ms.key_id, params.algorithm, ¶ms.data)
.await?;
let response_data = serde_json::to_value(Base64SignatureResponse {
signature: base64::engine::general_purpose::STANDARD.encode(&signature),
algorithm: params.algorithm,
})
.map_err(|e| HsmError::SerializationError(e.to_string()))?;
Ok(HsmResponse::success(request.id, Some(response_data)))
}
HsmOperation::Custom(op) if op == "sign_bitcoin_tx" => {
let params: BitcoinTxSignParams =
serde_json::from_value(request.parameters.clone()).map_err(|e| {
HsmError::InvalidParameters(format!(
"Invalid Bitcoin TX signing parameters: {}",
e
))
})?;
let mut psbt = bitcoin::psbt::Psbt::from_str(¶ms.psbt)
.map_err(|e| HsmError::InvalidParameters(format!("Invalid PSBT: {}", e)))?;
self.sign_bitcoin_transaction(¶ms.key_id, &mut psbt)
.await?;
let response_data = serde_json::json!({
"signed_psbt": psbt.to_string(),
"network": "testnet",
});
Ok(HsmResponse::success(request.id, Some(response_data)))
}
HsmOperation::Custom(op) if op == "unlock" => {
let params: UnlockParams = serde_json::from_value(request.parameters.clone())
.map_err(|e| {
HsmError::InvalidParameters(format!("Invalid unlock parameters: {}", e))
})?;
self.unlock(¶ms.pin).await?;
Ok(HsmResponse::success(request.id, None))
}
HsmOperation::Custom(op) if op == "get_diagnostics" => {
let diagnostics = self.get_diagnostics().await?;
let response_data = serde_json::to_value(diagnostics)
.map_err(|e| HsmError::SerializationError(e.to_string()))?;
Ok(HsmResponse::success(request.id, Some(response_data)))
}
_ => Err(HsmError::UnsupportedOperation(format!(
"{:?}",
request.operation
))),
}
}
}
#[derive(Debug, serde::Deserialize)]
struct SignParams {
key_id: String,
algorithm: SigningAlgorithm,
data: Vec<u8>,
}
#[derive(Debug, serde::Deserialize)]
struct BitcoinTxSignParams {
key_id: String,
psbt: String,
}
#[derive(Debug, serde::Deserialize)]
struct UnlockParams {
pin: String,
}
#[derive(Debug, serde::Serialize)]
struct Base64SignatureResponse {
signature: String,
algorithm: SigningAlgorithm,
}