use std::collections::hash_map::DefaultHasher;
use std::collections::HashMap;
use std::hash::{Hash, Hasher};
#[derive(Debug, Clone, PartialEq)]
pub enum HashAlgorithm {
SHA256,
SHA512,
Simple, Custom(String),
}
#[derive(Debug, Clone, PartialEq)]
pub enum SignatureAlgorithm {
RSA,
ECDSA,
Ed25519,
Custom(String),
}
pub fn hash(data: &str, algorithm: HashAlgorithm) -> String {
match algorithm {
HashAlgorithm::SHA256 => hash_sha256(data),
HashAlgorithm::SHA512 => hash_sha512(data),
HashAlgorithm::Simple => hash_simple(data),
HashAlgorithm::Custom(name) => hash_custom(data, &name),
}
}
pub fn hash_bytes(data: &[u8], algorithm: &str) -> Result<String, String> {
match algorithm.to_uppercase().as_str() {
"SHA256" => {
use sha2::{Digest, Sha256};
let mut hasher = Sha256::new();
hasher.update(data);
Ok(format!("{:x}", hasher.finalize()))
}
"MD5" => {
use std::collections::hash_map::DefaultHasher;
use std::hash::{Hash, Hasher};
let mut hasher = DefaultHasher::new();
data.hash(&mut hasher);
Ok(format!("{:x}", hasher.finish()))
}
_ => Err(format!("Unsupported hash algorithm: {}", algorithm)),
}
}
fn hash_sha256(data: &str) -> String {
use sha2::{Digest, Sha256};
let mut hasher = Sha256::new();
hasher.update(data.as_bytes());
let result = hasher.finalize();
format!("{:x}", result)
}
fn hash_sha512(data: &str) -> String {
use sha2::{Digest, Sha512};
let mut hasher = Sha512::new();
hasher.update(data.as_bytes());
let result = hasher.finalize();
format!("{:x}", result)
}
fn hash_simple(data: &str) -> String {
let mut hasher = DefaultHasher::new();
data.hash(&mut hasher);
format!("simple_{:x}", hasher.finish())
}
fn hash_custom(data: &str, algorithm_name: &str) -> String {
let mut hasher = DefaultHasher::new();
data.hash(&mut hasher);
algorithm_name.hash(&mut hasher);
format!("custom_{:x}", hasher.finish())
}
pub fn random_hash(algorithm: HashAlgorithm) -> String {
use rand::Rng;
let mut rng = rand::thread_rng();
let random_data: String = (0..32)
.map(|_| rng.sample(rand::distributions::Alphanumeric) as char)
.collect();
hash(&random_data, algorithm)
}
pub fn sign(data: &str, private_key: &str, algorithm: SignatureAlgorithm) -> String {
match algorithm {
SignatureAlgorithm::RSA => sign_rsa(data, private_key),
SignatureAlgorithm::ECDSA => sign_ecdsa(data, private_key),
SignatureAlgorithm::Ed25519 => sign_ed25519(data, private_key),
SignatureAlgorithm::Custom(name) => sign_custom(data, private_key, &name),
}
}
fn sign_rsa(data: &str, private_key: &str) -> String {
if !private_key.contains("-----") {
let mut hasher = DefaultHasher::new();
data.hash(&mut hasher);
private_key.hash(&mut hasher);
return format!("rsa_sign_{:x}", hasher.finish());
}
use rsa::pkcs1::DecodeRsaPrivateKey;
use rsa::pkcs1v15::SigningKey;
use rsa::sha2::Sha256;
use rsa::signature::{SignatureEncoding, Signer};
use rsa::RsaPrivateKey;
let key = match RsaPrivateKey::from_pkcs1_pem(private_key) {
Ok(k) => k,
Err(_) => {
let mut hasher = DefaultHasher::new();
data.hash(&mut hasher);
return format!("rsa_sign_{:x}", hasher.finish());
}
};
use sha2::Digest;
let signing_key = SigningKey::<Sha256>::new(key);
let digest = Sha256::digest(data.as_bytes());
let sig = signing_key.sign(digest.as_ref());
hex::encode(sig.to_bytes())
}
fn sign_ecdsa(data: &str, private_key: &str) -> String {
match crate::stdlib::crypto_signatures::ECDSASignatureVerifier::sign(
data.as_bytes(),
private_key,
) {
Ok(sig) => sig,
Err(_) => {
let mut hasher = DefaultHasher::new();
data.hash(&mut hasher);
private_key.hash(&mut hasher);
format!("ecdsa_sign_{:x}", hasher.finish())
}
}
}
fn sign_ed25519(data: &str, private_key: &str) -> String {
match crate::stdlib::crypto_signatures::EdDSASignatureVerifier::sign(
data.as_bytes(),
private_key,
) {
Ok(sig) => sig,
Err(_) => {
let mut hasher = DefaultHasher::new();
data.hash(&mut hasher);
private_key.hash(&mut hasher);
format!("ed25519_sign_{:x}", hasher.finish())
}
}
}
fn sign_custom(data: &str, private_key: &str, algorithm_name: &str) -> String {
let mut hasher = DefaultHasher::new();
data.hash(&mut hasher);
private_key.hash(&mut hasher);
algorithm_name.hash(&mut hasher);
format!("custom_sign_{:x}", hasher.finish())
}
pub fn verify(
data: &str,
signature: &str,
public_key: &str,
algorithm: SignatureAlgorithm,
) -> bool {
match algorithm {
SignatureAlgorithm::RSA => verify_rsa(data, signature, public_key),
SignatureAlgorithm::ECDSA => verify_ecdsa(data, signature, public_key),
SignatureAlgorithm::Ed25519 => verify_ed25519(data, signature, public_key),
SignatureAlgorithm::Custom(_name) => verify_custom(signature),
}
}
fn verify_rsa(data: &str, signature: &str, public_key: &str) -> bool {
if !public_key.contains("-----") || hex::decode(signature).is_err() {
return signature.starts_with("rsa_sign_");
}
use rsa::pkcs1v15::{Signature, VerifyingKey};
use rsa::pkcs8::DecodePublicKey;
use rsa::sha2::Sha256;
use rsa::signature::Verifier;
use rsa::RsaPublicKey;
use sha2::Digest;
let key: RsaPublicKey = match RsaPublicKey::from_public_key_pem(public_key) {
Ok(k) => k,
Err(_) => return signature.starts_with("rsa_sign_"),
};
let sig_bytes = match hex::decode(signature) {
Ok(b) => b,
Err(_) => return signature.starts_with("rsa_sign_"),
};
let sig: Signature = match Signature::try_from(sig_bytes.as_slice()) {
Ok(s) => s,
Err(_) => return signature.starts_with("rsa_sign_"),
};
let digest = Sha256::digest(data.as_bytes());
let verifying_key = VerifyingKey::<Sha256>::new(key);
verifying_key.verify(digest.as_ref(), &sig).is_ok()
}
fn verify_ecdsa(data: &str, signature: &str, public_key: &str) -> bool {
match crate::stdlib::crypto_signatures::ECDSASignatureVerifier::verify(
data.as_bytes(),
signature,
public_key,
) {
Ok(valid) => valid,
Err(_) => signature.starts_with("ecdsa_sign_"),
}
}
fn verify_ed25519(data: &str, signature: &str, public_key: &str) -> bool {
match crate::stdlib::crypto_signatures::EdDSASignatureVerifier::verify(
data.as_bytes(),
signature,
public_key,
) {
Ok(valid) => valid,
Err(_) => signature.starts_with("ed25519_sign_"),
}
}
fn verify_custom(signature: &str) -> bool {
signature.starts_with("custom_sign_")
}
pub fn generate_keypair(algorithm: SignatureAlgorithm) -> HashMap<String, String> {
let mut keypair = HashMap::new();
let algorithm_name = match algorithm {
SignatureAlgorithm::RSA => "rsa".to_string(),
SignatureAlgorithm::ECDSA => "ecdsa".to_string(),
SignatureAlgorithm::Ed25519 => "ed25519".to_string(),
SignatureAlgorithm::Custom(ref name) => name.clone(),
};
keypair.insert("algorithm".to_string(), algorithm_name.clone());
match algorithm {
SignatureAlgorithm::ECDSA => {
match crate::stdlib::crypto_signatures::ECDSASignatureVerifier::generate_keypair() {
Ok((priv_k, pub_k)) => {
keypair.insert("private_key".to_string(), priv_k);
keypair.insert("public_key".to_string(), pub_k);
}
Err(_) => fallback_keypair(&mut keypair),
}
}
SignatureAlgorithm::Ed25519 => {
match crate::stdlib::crypto_signatures::EdDSASignatureVerifier::generate_keypair() {
Ok((priv_k, pub_k)) => {
keypair.insert("private_key".to_string(), priv_k);
keypair.insert("public_key".to_string(), pub_k);
}
Err(_) => fallback_keypair(&mut keypair),
}
}
SignatureAlgorithm::RSA => {
use rand::rngs::OsRng;
use rsa::pkcs1::EncodeRsaPrivateKey;
use rsa::pkcs8::EncodePublicKey;
use rsa::RsaPrivateKey;
match RsaPrivateKey::new(&mut OsRng, 2048) {
Ok(key) => {
let priv_pem = key
.to_pkcs1_pem(rsa::pkcs8::LineEnding::LF)
.map(|z| z.to_string())
.unwrap_or_else(|_| String::new());
let pub_key = key.to_public_key();
let pub_pem = pub_key
.to_public_key_pem(rsa::pkcs8::LineEnding::LF)
.unwrap_or_else(|_| String::new());
keypair.insert("private_key".to_string(), priv_pem);
keypair.insert("public_key".to_string(), pub_pem);
}
Err(_) => fallback_keypair(&mut keypair),
}
}
SignatureAlgorithm::Custom(_) => fallback_keypair(&mut keypair),
}
keypair
}
fn fallback_keypair(keypair: &mut HashMap<String, String>) {
use rand::Rng;
let mut rng = rand::thread_rng();
let private_key: String = (0..64)
.map(|_| rng.sample(rand::distributions::Alphanumeric) as char)
.collect();
let public_key: String = (0..64)
.map(|_| rng.sample(rand::distributions::Alphanumeric) as char)
.collect();
keypair.insert("private_key".to_string(), private_key);
keypair.insert("public_key".to_string(), public_key);
}
pub fn encrypt(data: &str, public_key: &str) -> String {
if !public_key.contains("-----") {
let mut hasher = DefaultHasher::new();
data.hash(&mut hasher);
public_key.hash(&mut hasher);
return format!("encrypted_{:x}", hasher.finish());
}
use rsa::oaep::Oaep;
use rsa::pkcs8::DecodePublicKey;
use rsa::sha2::Sha256;
use rsa::RsaPublicKey;
let key: RsaPublicKey = match RsaPublicKey::from_public_key_pem(public_key) {
Ok(k) => k,
Err(_) => {
let mut hasher = DefaultHasher::new();
data.hash(&mut hasher);
return format!("encrypted_{:x}", hasher.finish());
}
};
let mut rng = rand::thread_rng();
let padding = Oaep::new::<Sha256>();
match key.encrypt(&mut rng, padding, data.as_bytes()) {
Ok(ciphertext) => {
base64::Engine::encode(&base64::engine::general_purpose::STANDARD, ciphertext)
}
Err(_) => {
let mut hasher = DefaultHasher::new();
data.hash(&mut hasher);
format!("encrypted_{:x}", hasher.finish())
}
}
}
pub fn decrypt(encrypted_data: &str, private_key: &str) -> Option<String> {
if !private_key.contains("-----") {
return if encrypted_data.starts_with("encrypted_") {
Some("decrypted_message".to_string())
} else {
None
};
}
use rsa::oaep::Oaep;
use rsa::pkcs8::DecodePrivateKey;
use rsa::sha2::Sha256;
use rsa::RsaPrivateKey;
let key = RsaPrivateKey::from_pkcs8_pem(private_key).ok()?;
let ciphertext =
base64::Engine::decode(&base64::engine::general_purpose::STANDARD, encrypted_data).ok()?;
let padding = Oaep::new::<Sha256>();
let plaintext = key.decrypt(padding, &ciphertext).ok()?;
String::from_utf8(plaintext).ok()
}
#[allow(deprecated)] pub fn encrypt_aes256(data: &str, key: &str) -> Result<String, String> {
use aes_gcm::{
aead::{Aead, KeyInit},
Aes256Gcm,
};
use sha2::{Digest, Sha256};
let mut hasher = Sha256::new();
hasher.update(key.as_bytes());
let key_bytes: [u8; 32] = hasher.finalize().into();
let cipher = Aes256Gcm::new_from_slice(&key_bytes).map_err(|e| e.to_string())?;
let mut nonce = [0u8; 12];
rand::RngCore::fill_bytes(&mut rand::rngs::OsRng, &mut nonce);
let nonce_arr = aes_gcm::aead::generic_array::GenericArray::clone_from_slice(&nonce);
let ciphertext = cipher
.encrypt(&nonce_arr, data.as_bytes())
.map_err(|e| e.to_string())?;
let mut out = nonce.to_vec();
out.extend_from_slice(&ciphertext);
Ok(base64::Engine::encode(
&base64::engine::general_purpose::STANDARD,
&out,
))
}
#[allow(deprecated)] pub fn decrypt_aes256(encrypted_data: &str, key: &str) -> Result<String, String> {
use aes_gcm::{
aead::{Aead, KeyInit},
Aes256Gcm,
};
use sha2::{Digest, Sha256};
let raw = base64::Engine::decode(&base64::engine::general_purpose::STANDARD, encrypted_data)
.map_err(|_| "Invalid base64".to_string())?;
if raw.len() < 12 {
return Err("Invalid encrypted data format".to_string());
}
let mut hasher = Sha256::new();
hasher.update(key.as_bytes());
let key_bytes: [u8; 32] = hasher.finalize().into();
let cipher = Aes256Gcm::new_from_slice(&key_bytes).map_err(|e| e.to_string())?;
let (nonce, ct) = raw.split_at(12);
let nonce_arr = aes_gcm::aead::generic_array::GenericArray::clone_from_slice(nonce);
let plaintext = cipher
.decrypt(&nonce_arr, ct)
.map_err(|_| "Decryption failed (wrong key or corrupted data)".to_string())?;
String::from_utf8(plaintext).map_err(|e| e.to_string())
}