haveno 0.1.5

Haveno - secure P2P trading software with Monero integration
Documentation
use base64::{engine::general_purpose, Engine};
use rsa::{pkcs1::{DecodeRsaPrivateKey, EncodeRsaPublicKey}, RsaPrivateKey, RsaPublicKey};
use anyhow::{Result, Context};
use std::fs;
use hex::FromHex;
use openssl::pkey::PKey;
use openssl::sign::Signer;
use sha2::{Sha256, Digest};
use openssl::dsa::Dsa;
use openssl::sha::sha256;
use crate::utils::config;

pub async fn load_signing_key_old() -> Result<RsaPrivateKey> {
    let json = fs::read_to_string("config.json")?;
    let config: config::Config = serde_json::from_str(&json)?;
    let hex_str = config.secret.trim();

    let secret_bytes: Vec<u8> = Vec::from_hex(hex_str)
        .context("Secret must be a valid hex string")?;

    let key = RsaPrivateKey::from_pkcs1_der(&secret_bytes)
        .context("Failed to parse RSA private key from DER")?;

    Ok(key)
}

/// Decode the hex-encoded private key, and treat it as DER-encoded PKCS#8
pub async fn load_private_key() -> Result<String> {
    let json = std::fs::read_to_string("config.json")?;
    let config: crate::utils::config::Config = serde_json::from_str(&json)?;
    let priv_key = config.secret.trim();

    Ok((&priv_key).to_string())
}

/// Sign a message using a hex-encoded 32-byte private key
fn sign_with_dsa(message: &[u8], hex_key: &str) -> Result<(String, Vec<u8>), Box<dyn std::error::Error>> {
    // Decode hex string
    let priv_bytes: [u8; 32] = <[u8; 32]>::from_hex(hex_key)?;

    // Create new DSA key parameters (p, q, g) — must match Java!
    // In reality, these must be generated or hardcoded to match the server’s expectation
    let dsa = Dsa::generate(2048)?;  // generates (p, q, g) automatically

    // Replace private key component
    let dsa = Dsa::from_private_components(
        dsa.p().to_owned()?,
        dsa.q().to_owned()?,
        dsa.g().to_owned()?,
        openssl::bn::BigNum::from_slice(&priv_bytes)?,
        dsa.pub_key().to_owned()?
    )?;

    // Hash the message
    let digest = sha256(message);

    // Sign
    let pkey = PKey::from_dsa(dsa)?;
    let mut signer = Signer::new_without_digest(&pkey)?;
    signer.update(&digest)?;
    let signature = signer.sign_to_vec()?;

    // Get public key as DER (X.509)
    let pubkey_der = pkey.public_key_to_der()?; // Java expects this format

    Ok((general_purpose::STANDARD.encode(signature), pubkey_der))
}

pub fn get_pubkey_der_bytes(rsa_key: &RsaPrivateKey) -> Result<Vec<u8>> {
    let pubkey: RsaPublicKey = rsa_key.to_public_key();
    let der = pubkey.to_pkcs1_der().unwrap().into_vec();
    Ok(der)
}

pub fn sign_with_dsa_pkcs8(data: Vec<u8>, der_private_key: &[u8]) -> Result<(Vec<u8>, Vec<u8>), Box<dyn std::error::Error>> {
    // Load private key from DER (PKCS#8 format, generated by Java)
    let pkey = PKey::private_key_from_der(der_private_key)?;
    
    // Pre-hash with SHA256 (to match Java's SHA256withDSA)
    let digest = Sha256::digest(&data);

    // Sign digest
    let mut signer = Signer::new_without_digest(&pkey)?;
    signer.update(&digest)?;
    let signature = signer.sign_to_vec()?;

    // Extract public key from private key (X.509 DER)
    let pubkey_der = pkey.public_key_to_der()?;

    Ok((signature, pubkey_der))
}

pub async fn decode_signature_base64(sig_base64: &str) -> Result<Vec<u8>, base64::DecodeError> {
    general_purpose::STANDARD.decode(sig_base64)
}