use qssh::crypto::SymmetricCrypto;
use qssh::{QsshConfig, PqAlgorithm, QsshError};
use std::collections::HashSet;
#[test]
fn test_symmetric_encryption() {
let key = vec![0x42; 32];
let crypto = SymmetricCrypto::from_shared_secret(&key).unwrap();
let plaintext = b"Hello, quantum world!";
let (ciphertext, nonce) = crypto.encrypt(plaintext).unwrap();
assert_ne!(ciphertext, plaintext);
assert_eq!(nonce.len(), 12);
let decrypted = crypto.decrypt(&ciphertext, &nonce).unwrap();
assert_eq!(decrypted, plaintext);
}
#[test]
fn test_encryption_uniqueness() {
let key = vec![0x42; 32];
let crypto = SymmetricCrypto::from_shared_secret(&key).unwrap();
let plaintext = b"Test message";
let (ct1, nonce1) = crypto.encrypt(plaintext).unwrap();
let (ct2, nonce2) = crypto.encrypt(plaintext).unwrap();
assert_ne!(nonce1, nonce2);
assert_ne!(ct1, ct2);
}
#[test]
fn test_tampering_detection() {
let key = vec![0x42; 32];
let crypto = SymmetricCrypto::from_shared_secret(&key).unwrap();
let plaintext = b"Sensitive data";
let (mut ciphertext, nonce) = crypto.encrypt(plaintext).unwrap();
ciphertext[0] ^= 0xFF;
assert!(crypto.decrypt(&ciphertext, &nonce).is_err());
}
#[test]
fn test_nonce_uniqueness() {
let key = vec![0x42; 32];
let crypto = SymmetricCrypto::from_shared_secret(&key).unwrap();
let mut nonces = HashSet::new();
for i in 0..1000 {
let (_, nonce) = crypto.encrypt(b"test").unwrap();
assert!(nonces.insert(nonce), "Nonce reused at iteration {}", i);
}
assert_eq!(nonces.len(), 1000);
}
#[test]
fn test_different_key_sizes() {
let short_key = vec![0x42; 16];
assert!(SymmetricCrypto::from_shared_secret(&short_key).is_err());
let valid_key = vec![0x42; 32];
assert!(SymmetricCrypto::from_shared_secret(&valid_key).is_ok());
let long_key = vec![0x42; 64];
assert!(SymmetricCrypto::from_shared_secret(&long_key).is_ok());
}
#[test]
fn test_config_defaults() {
let config = QsshConfig::default();
assert_eq!(config.server, "localhost:22222");
assert_eq!(config.username, "user");
assert_eq!(config.pq_algorithm, PqAlgorithm::Falcon512);
assert!(!config.use_qkd);
assert_eq!(config.key_rotation_interval, 3600);
assert!(config.port_forwards.is_empty());
}
#[test]
fn test_config_serialization() {
let config = QsshConfig {
server: "quantum.server:2222".to_string(),
username: "alice".to_string(),
port_forwards: vec![],
use_qkd: true,
pq_algorithm: PqAlgorithm::SphincsPlus,
key_rotation_interval: 1800,
};
let json = serde_json::to_string(&config).unwrap();
let parsed: QsshConfig = serde_json::from_str(&json).unwrap();
assert_eq!(parsed.server, config.server);
assert_eq!(parsed.use_qkd, config.use_qkd);
assert_eq!(parsed.pq_algorithm, PqAlgorithm::SphincsPlus);
}
#[test]
fn test_error_display() {
let errors = vec![
QsshError::Connection("Connection refused".to_string()),
QsshError::Crypto("Invalid key".to_string()),
QsshError::Qkd("QKD unavailable".to_string()),
QsshError::Protocol("Version mismatch".to_string()),
];
for error in errors {
let msg = error.to_string();
assert!(!msg.is_empty());
match error {
QsshError::Connection(_) => assert!(msg.contains("Connection")),
QsshError::Crypto(_) => assert!(msg.contains("Cryptographic")),
QsshError::Qkd(_) => assert!(msg.contains("QKD")),
QsshError::Protocol(_) => assert!(msg.contains("Protocol")),
_ => {}
}
}
}
#[test]
fn test_encryption_performance() {
use std::time::Instant;
let key = vec![0x42; 32];
let crypto = SymmetricCrypto::from_shared_secret(&key).unwrap();
let data = vec![0xAB; 10240]; let iterations = 100;
let start = Instant::now();
for _ in 0..iterations {
let (ct, nonce) = crypto.encrypt(&data).unwrap();
let _ = crypto.decrypt(&ct, &nonce).unwrap();
}
let elapsed = start.elapsed();
let throughput_mbps = (data.len() * iterations * 2) as f64
/ elapsed.as_secs_f64() / 1_000_000.0;
println!("AES-256-GCM throughput: {:.2} MB/s", throughput_mbps);
assert!(throughput_mbps > 3.0, "Encryption too slow: {:.2} MB/s", throughput_mbps);
}
#[test]
fn test_large_data_encryption() {
let key = vec![0x42; 32];
let crypto = SymmetricCrypto::from_shared_secret(&key).unwrap();
let sizes = vec![
1, 100, 10240, 1048576, ];
for size in sizes {
let data = vec![0xCD; size];
let (ct, nonce) = crypto.encrypt(&data).unwrap();
let decrypted = crypto.decrypt(&ct, &nonce).unwrap();
assert_eq!(decrypted, data, "Failed for size {}", size);
}
}