use crate::{QsshError, Result};
use pqcrypto_sphincsplus::sphincssha256128ssimple as sphincs;
use pqcrypto_falcon::falcon512;
use pqcrypto_traits::sign::{PublicKey as SignPublicKey, SignedMessage as SignedMessageTrait};
use aes_gcm::{
aead::{Aead, AeadCore, KeyInit, OsRng},
Aes256Gcm, Nonce,
};
use rand::RngCore;
pub mod kdf;
pub mod quantum_cipher;
pub mod cipher_choice;
pub mod qrng_integration;
#[cfg(test)]
pub mod test_helpers;
pub use kdf::{SessionKeyDerivation, SessionKeys};
pub use quantum_cipher::QuantumCipher;
pub use cipher_choice::{CipherAlgorithm, UniversalCipher};
pub use qrng_integration::{QuantumRng, QrngConfig};
pub struct PqSignature {
pub sphincs_sk: sphincs::SecretKey,
pub sphincs_pk: sphincs::PublicKey,
}
impl PqSignature {
pub fn new() -> Result<Self> {
let (sphincs_pk, sphincs_sk) = sphincs::keypair();
Ok(Self { sphincs_sk, sphincs_pk })
}
pub fn secret_bytes(&self) -> Vec<u8> {
use pqcrypto_traits::sign::SecretKey;
self.sphincs_sk.as_bytes().to_vec()
}
pub fn public_bytes(&self) -> Vec<u8> {
use pqcrypto_traits::sign::PublicKey;
self.sphincs_pk.as_bytes().to_vec()
}
}
pub struct PqKeyExchange {
pub sphincs_sk: sphincs::SecretKey,
pub sphincs_pk: sphincs::PublicKey,
pub falcon_sk: falcon512::SecretKey,
pub falcon_pk: falcon512::PublicKey,
}
impl PqKeyExchange {
pub fn new() -> Result<Self> {
let qrng_available = std::env::var("QSSH_QRNG_ENDPOINT").is_ok() ||
std::env::var("QSSH_KIRQ_ENDPOINT").is_ok();
if qrng_available {
log::info!("QRNG endpoint detected - keys will use quantum entropy");
}
let (sphincs_pk, sphincs_sk) = sphincs::keypair();
let (falcon_pk, falcon_sk) = falcon512::keypair();
Ok(Self {
sphincs_sk,
sphincs_pk,
falcon_sk,
falcon_pk,
})
}
pub fn create_key_share(&self) -> Result<(Vec<u8>, Vec<u8>)> {
let mut ephemeral_secret = vec![0u8; 32];
if std::env::var("QSSH_QRNG_ENDPOINT").is_ok() {
log::debug!("Using QRNG-enhanced entropy for ephemeral key share");
}
rand::thread_rng().fill_bytes(&mut ephemeral_secret);
let signature = falcon512::detached_sign(&ephemeral_secret, &self.falcon_sk);
use pqcrypto_traits::sign::DetachedSignature as DetachedSignatureTrait;
Ok((ephemeral_secret, signature.as_bytes().to_vec()))
}
pub fn process_key_share(
&self,
peer_falcon_pk: &[u8],
peer_share: &[u8],
peer_signature: &[u8],
) -> Result<Vec<u8>> {
use pqcrypto_traits::sign::PublicKey as SignPublicKeyTrait;
if peer_share.len() != 32 {
return Err(QsshError::Crypto(format!(
"Invalid key share size: got {}, expected 32",
peer_share.len()
)));
}
use pqcrypto_traits::sign::{PublicKey as PubKey, DetachedSignature};
let pk = match falcon512::PublicKey::from_bytes(peer_falcon_pk) {
Ok(key) => key,
Err(e) => {
log::error!("Failed to parse Falcon public key of size {}: {:?}",
peer_falcon_pk.len(), e);
return Err(QsshError::Crypto(format!("Invalid Falcon public key: {:?}", e)));
}
};
let sig = match falcon512::DetachedSignature::from_bytes(peer_signature) {
Ok(signature) => signature,
Err(e) => {
log::error!("Failed to parse Falcon detached signature of size {}: {:?}",
peer_signature.len(), e);
return Err(QsshError::Crypto(format!("Invalid Falcon signature: {:?}", e)));
}
};
match falcon512::verify_detached_signature(&sig, peer_share, &pk) {
Ok(_) => {
log::debug!("Falcon signature verified successfully");
}
Err(_) => {
log::error!("Falcon signature verification failed");
return Err(QsshError::Crypto("Invalid Falcon signature".into()));
}
}
Ok(peer_share.to_vec())
}
pub fn compute_shared_secret(
&self,
our_share: &[u8],
peer_share: &[u8],
client_random: &[u8],
server_random: &[u8],
) -> Vec<u8> {
use sha3::{Sha3_256, Digest};
let mut hasher = Sha3_256::new();
hasher.update(b"QSSH-FALCON-v2");
if our_share < peer_share {
hasher.update(our_share);
hasher.update(peer_share);
} else {
hasher.update(peer_share);
hasher.update(our_share);
}
hasher.update(client_random);
hasher.update(server_random);
hasher.finalize().to_vec()
}
pub fn sign(&self, message: &[u8]) -> Result<Vec<u8>> {
let signature = sphincs::sign(message, &self.sphincs_sk);
use SignedMessageTrait;
Ok(signature.as_bytes().to_vec())
}
pub fn sign_falcon(&self, message: &[u8]) -> Result<Vec<u8>> {
let signature = falcon512::sign(message, &self.falcon_sk);
use SignedMessageTrait;
Ok(signature.as_bytes().to_vec())
}
pub fn secret_bytes(&self) -> Vec<u8> {
use pqcrypto_traits::sign::SecretKey;
self.falcon_sk.as_bytes().to_vec()
}
pub fn public_bytes(&self) -> Vec<u8> {
use pqcrypto_traits::sign::PublicKey;
self.falcon_pk.as_bytes().to_vec()
}
pub fn verify(&self, message: &[u8], signature: &[u8], public_key: &[u8]) -> Result<bool> {
let sig = sphincs::SignedMessage::from_bytes(signature)
.map_err(|e| QsshError::Crypto(format!("Invalid signature: {:?}", e)))?;
let pk = sphincs::PublicKey::from_bytes(public_key)
.map_err(|e| QsshError::Crypto(format!("Invalid public key: {:?}", e)))?;
match sphincs::open(&sig, &pk) {
Ok(msg) => Ok(msg == message),
Err(_) => Ok(false)
}
}
pub fn verify_falcon(&self, message: &[u8], signature: &[u8], public_key: &[u8]) -> Result<bool> {
use pqcrypto_traits::sign::{PublicKey as PubKey, DetachedSignature};
let sig = falcon512::DetachedSignature::from_bytes(signature)
.map_err(|e| QsshError::Crypto(format!("Invalid Falcon signature: {:?}", e)))?;
let pk = falcon512::PublicKey::from_bytes(public_key)
.map_err(|e| QsshError::Crypto(format!("Invalid Falcon public key: {:?}", e)))?;
match falcon512::verify_detached_signature(&sig, message, &pk) {
Ok(_) => Ok(true),
Err(_) => Ok(false)
}
}
}
pub struct SymmetricCrypto {
cipher: Aes256Gcm,
}
impl SymmetricCrypto {
pub fn from_shared_secret(shared_secret: &[u8]) -> Result<Self> {
if shared_secret.len() < 32 {
return Err(QsshError::Crypto("Shared secret too short".into()));
}
let key = aes_gcm::Key::<Aes256Gcm>::from_slice(&shared_secret[..32]);
let cipher = Aes256Gcm::new(key);
Ok(Self { cipher })
}
pub fn encrypt(&self, plaintext: &[u8]) -> Result<(Vec<u8>, Vec<u8>)> {
let nonce = Aes256Gcm::generate_nonce(&mut OsRng);
let ciphertext = self.cipher
.encrypt(&nonce, plaintext)
.map_err(|e| QsshError::Crypto(format!("Encryption failed: {}", e)))?;
Ok((ciphertext, nonce.to_vec()))
}
pub fn decrypt(&self, ciphertext: &[u8], nonce: &[u8]) -> Result<Vec<u8>> {
let nonce = Nonce::from_slice(nonce);
let plaintext = self.cipher
.decrypt(nonce, ciphertext)
.map_err(|e| QsshError::Crypto(format!("Decryption failed: {}", e)))?;
Ok(plaintext)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[allow(dead_code)]
fn test_falcon_key_agreement() {
let alice = PqKeyExchange::new().unwrap();
let bob = PqKeyExchange::new().unwrap();
let (alice_share, alice_sig) = alice.create_key_share().unwrap();
let verified_alice_share = bob.process_key_share(
alice.falcon_pk.as_bytes(),
&alice_share,
&alice_sig
).unwrap();
assert_eq!(alice_share, verified_alice_share);
let (bob_share, bob_sig) = bob.create_key_share().unwrap();
let verified_bob_share = alice.process_key_share(
bob.falcon_pk.as_bytes(),
&bob_share,
&bob_sig
).unwrap();
assert_eq!(bob_share, verified_bob_share);
let client_random = vec![0x11; 32];
let server_random = vec![0x22; 32];
let alice_secret = alice.compute_shared_secret(
&alice_share,
&bob_share,
&client_random,
&server_random
);
let bob_secret = bob.compute_shared_secret(
&bob_share,
&alice_share,
&client_random,
&server_random
);
assert_eq!(alice_secret, bob_secret);
}
#[allow(dead_code)]
fn test_falcon_signatures() {
let signer = PqKeyExchange::new().unwrap();
let message = b"Test message for Falcon";
let signature = signer.sign_falcon(message).unwrap();
let valid = signer.verify_falcon(message, &signature, signer.falcon_pk.as_bytes()).unwrap();
assert!(valid);
let wrong_message = b"Wrong message";
let invalid = signer.verify_falcon(wrong_message, &signature, signer.falcon_pk.as_bytes()).unwrap();
assert!(!invalid);
}
#[test]
fn test_symmetric_crypto() {
let secret = vec![0x42; 32];
let crypto = SymmetricCrypto::from_shared_secret(&secret).expect("Failed to create crypto");
let plaintext = b"Hello, quantum world!";
let (ciphertext, nonce) = crypto.encrypt(plaintext).expect("Failed to encrypt");
let decrypted = crypto.decrypt(&ciphertext, &nonce).expect("Failed to decrypt");
assert_eq!(plaintext, &decrypted[..]);
}
}