use crate::security::zrtp::packet::{ZrtpMessageType, ZrtpPacket, ZrtpVersion};
use crate::security::zrtp::{
Zrtp, ZrtpAuthTag, ZrtpCipher, ZrtpConfig, ZrtpHash, ZrtpKeyAgreement, ZrtpRole, ZrtpSasType,
};
use crate::security::SecurityKeyExchange;
use crate::srtp::SRTP_AES128_CM_SHA1_80;
#[test]
fn test_zrtp_packet_formats() {
let mut hello = ZrtpPacket::new(ZrtpMessageType::Hello);
hello.set_version(ZrtpVersion::V12);
hello.set_client_id("RVOIP ZRTP Test");
let mut zid = [0u8; 12];
for i in 0..12 {
zid[i] = i as u8;
}
hello.set_zid(&zid);
hello.add_cipher(ZrtpCipher::Aes1);
hello.add_hash(ZrtpHash::S256);
hello.add_auth_tag(ZrtpAuthTag::HS80);
hello.add_key_agreement(ZrtpKeyAgreement::EC25);
hello.add_sas_type(ZrtpSasType::B32);
let hello_bytes = hello.to_bytes();
assert!(!hello_bytes.is_empty());
let parsed_hello = ZrtpPacket::parse(&hello_bytes).expect("Failed to parse Hello packet");
assert_eq!(parsed_hello.message_type(), ZrtpMessageType::Hello);
assert_eq!(parsed_hello.zid().unwrap(), zid);
assert!(!parsed_hello.ciphers().is_empty());
assert!(!parsed_hello.hashes().is_empty());
assert!(!parsed_hello.auth_tags().is_empty());
assert!(!parsed_hello.key_agreements().is_empty());
assert!(!parsed_hello.sas_types().is_empty());
let mut commit = ZrtpPacket::new(ZrtpMessageType::Commit);
commit.set_zid(&zid);
commit.set_cipher(ZrtpCipher::Aes1);
commit.set_hash(ZrtpHash::S256);
commit.set_auth_tag(ZrtpAuthTag::HS80);
commit.set_key_agreement(ZrtpKeyAgreement::EC25);
commit.set_sas_type(ZrtpSasType::B32);
let commit_bytes = commit.to_bytes();
let parsed_commit = ZrtpPacket::parse(&commit_bytes).expect("Failed to parse Commit packet");
assert_eq!(parsed_commit.message_type(), ZrtpMessageType::Commit);
assert_eq!(parsed_commit.zid().unwrap(), zid);
assert_eq!(parsed_commit.cipher().unwrap(), ZrtpCipher::Aes1);
assert_eq!(parsed_commit.hash().unwrap(), ZrtpHash::S256);
assert_eq!(parsed_commit.auth_tag().unwrap(), ZrtpAuthTag::HS80);
assert_eq!(
parsed_commit.key_agreement().unwrap(),
ZrtpKeyAgreement::EC25
);
assert_eq!(parsed_commit.sas_type().unwrap(), ZrtpSasType::B32);
}
#[test]
fn test_zrtp_hash_functions() {
use crate::security::zrtp::hash::ZrtpHash;
let data = b"test data for hashing";
let hash = ZrtpHash::sha256(data);
assert_eq!(hash.len(), 32);
let hash2 = ZrtpHash::sha256(data);
assert_eq!(hash, hash2);
let data2 = b"different test data";
let hash3 = ZrtpHash::sha256(data2);
assert_ne!(hash, hash3);
let hash4 = ZrtpHash::sha384(data);
assert_eq!(hash4.len(), 48);
}
#[test]
fn test_zrtp_basic_init() {
let initiator_config = ZrtpConfig {
ciphers: vec![ZrtpCipher::Aes1],
hashes: vec![ZrtpHash::S256],
auth_tags: vec![ZrtpAuthTag::HS80],
key_agreements: vec![ZrtpKeyAgreement::EC25],
sas_types: vec![ZrtpSasType::B32],
client_id: "RVOIP ZRTP Initiator".to_string(),
srtp_profile: SRTP_AES128_CM_SHA1_80,
};
let mut initiator = Zrtp::new(initiator_config, ZrtpRole::Initiator);
let result = initiator.init();
assert!(
result.is_ok(),
"Failed to initialize initiator: {:?}",
result
);
let hello_result = initiator.create_hello();
assert!(
hello_result.is_ok(),
"Failed to create Hello message: {:?}",
hello_result
);
let hello = hello_result.unwrap();
assert_eq!(hello.message_type(), ZrtpMessageType::Hello);
}
#[test]
fn test_zrtp_config() {
let config = ZrtpConfig {
ciphers: vec![ZrtpCipher::Aes1, ZrtpCipher::Aes3, ZrtpCipher::TwoF],
hashes: vec![ZrtpHash::S256, ZrtpHash::S384],
auth_tags: vec![ZrtpAuthTag::HS80, ZrtpAuthTag::HS32],
key_agreements: vec![
ZrtpKeyAgreement::EC25,
ZrtpKeyAgreement::DH3k,
ZrtpKeyAgreement::DH4k,
ZrtpKeyAgreement::EC38,
],
sas_types: vec![ZrtpSasType::B32, ZrtpSasType::B32E],
client_id: "RVOIP ZRTP Test".to_string(),
srtp_profile: SRTP_AES128_CM_SHA1_80,
};
let zrtp = Zrtp::new(config, ZrtpRole::Initiator);
assert_eq!(zrtp.role, ZrtpRole::Initiator);
assert!(!zrtp.is_complete());
}
#[test]
fn test_zrtp_sas_generation() {
let config = ZrtpConfig {
ciphers: vec![ZrtpCipher::Aes1],
hashes: vec![ZrtpHash::S256],
auth_tags: vec![ZrtpAuthTag::HS80],
key_agreements: vec![ZrtpKeyAgreement::EC25],
sas_types: vec![ZrtpSasType::B32],
client_id: "RVOIP ZRTP SAS Test".to_string(),
srtp_profile: SRTP_AES128_CM_SHA1_80,
};
let mut zrtp = Zrtp::new(config, ZrtpRole::Initiator);
zrtp.shared_secret = Some(vec![0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08]);
zrtp.hello_hash = Some([0x11; 32]);
zrtp.peer_hello_hash = Some([0x22; 32]);
zrtp.selected_sas_type = Some(ZrtpSasType::B32);
zrtp.state = crate::security::zrtp::ZrtpState::Completed;
let sas_result = zrtp.generate_sas();
assert!(
sas_result.is_ok(),
"SAS generation failed: {:?}",
sas_result
);
let sas = sas_result.unwrap();
assert_eq!(sas.len(), 4, "SAS should be 4 characters for B32 type");
let display_result = zrtp.get_sas_display();
assert!(
display_result.is_ok(),
"SAS display generation failed: {:?}",
display_result
);
let display = display_result.unwrap();
assert!(
display.contains(&sas),
"SAS display should contain the generated SAS"
);
assert!(
display.contains("SAS:"),
"SAS display should be formatted properly"
);
}
#[test]
fn test_zrtp_sas_verification() {
let config = ZrtpConfig {
ciphers: vec![ZrtpCipher::Aes1],
hashes: vec![ZrtpHash::S256],
auth_tags: vec![ZrtpAuthTag::HS80],
key_agreements: vec![ZrtpKeyAgreement::EC25],
sas_types: vec![ZrtpSasType::B32],
client_id: "RVOIP ZRTP Verification Test".to_string(),
srtp_profile: SRTP_AES128_CM_SHA1_80,
};
let mut zrtp = Zrtp::new(config, ZrtpRole::Initiator);
zrtp.shared_secret = Some(vec![0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08]);
zrtp.hello_hash = Some([0x11; 32]);
zrtp.peer_hello_hash = Some([0x22; 32]);
zrtp.selected_sas_type = Some(ZrtpSasType::B32);
zrtp.state = crate::security::zrtp::ZrtpState::Completed;
let sas = zrtp.generate_sas().unwrap();
let verify_correct = zrtp.verify_sas(&sas);
assert!(verify_correct.is_ok(), "SAS verification should work");
assert!(verify_correct.unwrap(), "Correct SAS should verify");
let verify_case = zrtp.verify_sas(&sas.to_lowercase());
assert!(
verify_case.is_ok(),
"Case-insensitive SAS verification should work"
);
assert!(verify_case.unwrap(), "Case-insensitive SAS should verify");
let verify_incorrect = zrtp.verify_sas("WXYZ");
assert!(
verify_incorrect.is_ok(),
"SAS verification should not error"
);
assert!(
!verify_incorrect.unwrap(),
"Incorrect SAS should not verify"
);
}
#[test]
fn test_zrtp_sas_different_types() {
let base_config = ZrtpConfig {
ciphers: vec![ZrtpCipher::Aes1],
hashes: vec![ZrtpHash::S256],
auth_tags: vec![ZrtpAuthTag::HS80],
key_agreements: vec![ZrtpKeyAgreement::EC25],
sas_types: vec![ZrtpSasType::B32],
client_id: "RVOIP ZRTP SAS Type Test".to_string(),
srtp_profile: SRTP_AES128_CM_SHA1_80,
};
let mut zrtp_b32 = Zrtp::new(base_config.clone(), ZrtpRole::Initiator);
zrtp_b32.shared_secret = Some(vec![0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08]);
zrtp_b32.hello_hash = Some([0x11; 32]);
zrtp_b32.peer_hello_hash = Some([0x22; 32]);
zrtp_b32.selected_sas_type = Some(ZrtpSasType::B32);
zrtp_b32.state = crate::security::zrtp::ZrtpState::Completed;
let sas_b32 = zrtp_b32.generate_sas().unwrap();
assert_eq!(sas_b32.len(), 4, "B32 SAS should be 4 characters");
assert!(
sas_b32.chars().all(|c| c.is_ascii_alphanumeric()),
"B32 SAS should be alphanumeric"
);
let mut zrtp_b32e = Zrtp::new(base_config, ZrtpRole::Initiator);
zrtp_b32e.shared_secret = Some(vec![0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08]);
zrtp_b32e.hello_hash = Some([0x11; 32]);
zrtp_b32e.peer_hello_hash = Some([0x22; 32]);
zrtp_b32e.selected_sas_type = Some(ZrtpSasType::B32E);
zrtp_b32e.state = crate::security::zrtp::ZrtpState::Completed;
let sas_b32e = zrtp_b32e.generate_sas().unwrap();
assert_eq!(sas_b32e.len(), 4, "B32E SAS should be 4 characters");
assert!(
sas_b32e.chars().all(|c| c.is_ascii_digit()),
"B32E SAS should be numeric"
);
}
#[test]
fn test_zrtp_sas_deterministic() {
let config = ZrtpConfig {
ciphers: vec![ZrtpCipher::Aes1],
hashes: vec![ZrtpHash::S256],
auth_tags: vec![ZrtpAuthTag::HS80],
key_agreements: vec![ZrtpKeyAgreement::EC25],
sas_types: vec![ZrtpSasType::B32],
client_id: "RVOIP ZRTP Deterministic Test".to_string(),
srtp_profile: SRTP_AES128_CM_SHA1_80,
};
let mut zrtp1 = Zrtp::new(config.clone(), ZrtpRole::Initiator);
let mut zrtp2 = Zrtp::new(config, ZrtpRole::Responder);
let shared_secret = vec![0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08];
let hello_hash_i = [0x11; 32]; let hello_hash_r = [0x22; 32];
zrtp1.shared_secret = Some(shared_secret.clone());
zrtp1.hello_hash = Some(hello_hash_i); zrtp1.peer_hello_hash = Some(hello_hash_r); zrtp1.selected_sas_type = Some(ZrtpSasType::B32);
zrtp1.state = crate::security::zrtp::ZrtpState::Completed;
zrtp2.shared_secret = Some(shared_secret);
zrtp2.hello_hash = Some(hello_hash_r); zrtp2.peer_hello_hash = Some(hello_hash_i); zrtp2.selected_sas_type = Some(ZrtpSasType::B32);
zrtp2.state = crate::security::zrtp::ZrtpState::Completed;
let sas1 = zrtp1.generate_sas().unwrap();
let sas2 = zrtp2.generate_sas().unwrap();
assert_eq!(sas1, sas2, "Both endpoints should generate the same SAS");
}