use std::collections::VecDeque;
use zrtp::*;
#[derive(Default)]
struct MemoryLink {
queue: VecDeque<QueuedPacket>,
}
enum QueuedPacket {
ToA(Vec<u8>),
ToB(Vec<u8>),
}
impl MemoryLink {
fn send(&mut self, from_a: bool, packet: Packet) {
let bytes = packet.encode();
if from_a {
self.queue.push_back(QueuedPacket::ToB(bytes));
} else {
self.queue.push_back(QueuedPacket::ToA(bytes));
}
}
fn pop(&mut self) -> Option<(bool, Packet)> {
match self.queue.pop_front()? {
QueuedPacket::ToA(bytes) => {
Some((false, Packet::decode(&bytes).expect("valid ZRTP packet")))
}
QueuedPacket::ToB(bytes) => {
Some((true, Packet::decode(&bytes).expect("valid ZRTP packet")))
}
}
}
}
struct Peer {
is_a: bool,
sequence: u16,
ssrc: u32,
engine: ZrtpEngine<MemorySharedSecretStore>,
}
impl Peer {
fn new(is_a: bool, role: Role, hello: Hello) -> Self {
Self {
is_a,
sequence: if is_a { 1 } else { 100 },
ssrc: if is_a { 0x1111_2222 } else { 0x3333_4444 },
engine: ZrtpEngine::new(role, hello, MemorySharedSecretStore::default()),
}
}
fn emit(&mut self, message: Message, link: &mut MemoryLink) {
let packet = Packet {
sequence: self.sequence,
ssrc: self.ssrc,
message,
};
self.sequence = self.sequence.wrapping_add(1);
link.send(self.is_a, packet);
}
fn handle_packet(&mut self, packet: Packet, link: &mut MemoryLink) {
let events = self
.engine
.receive(&packet.message)
.expect("ZRTP state transition should succeed");
for event in events {
match event {
EngineEvent::Send(message) => self.emit(message, link),
EngineEvent::Negotiated(algos) => println!("negotiated: {:?}", algos),
EngineEvent::SasReady(sas) => println!("SAS ready: {sas}"),
EngineEvent::SecureOn => println!("secure channel established"),
EngineEvent::SecureOff => println!("secure channel cleared"),
EngineEvent::Error(code) => println!("error: {:?}", code),
}
}
}
}
fn hello(zid: [u8; 12], client_id: [u8; 16]) -> Hello {
Hello {
version: VERSION_1_10,
client_id,
hash_image_h3: [0; 32],
zid,
signature_capable: false,
mitm_capable: false,
passive_capable: false,
hashes: vec![algos::HASH_S256],
ciphers: vec![algos::CIPHER_AES1],
auth_tags: vec![algos::AUTH_HS32],
key_agreements: vec![algos::KEYAGREE_EC25],
sas_types: vec![algos::SAS_B32],
mac: [0; 8],
}
}
fn main() {
let mut link = MemoryLink::default();
let mut initiator = Peer::new(true, Role::Initiator, hello([1; 12], *b"zrtr-init-demo "));
let mut responder = Peer::new(false, Role::Responder, hello([2; 12], *b"zrtr-rsp-demo "));
for event in initiator.engine.start() {
if let EngineEvent::Send(message) = event {
initiator.emit(message, &mut link);
}
}
for event in responder.engine.start() {
if let EngineEvent::Send(message) = event {
responder.emit(message, &mut link);
}
}
while let Some((to_b, packet)) = link.pop() {
if to_b {
responder.handle_packet(packet, &mut link);
} else {
initiator.handle_packet(packet, &mut link);
}
}
println!("initiator SAS: {:?}", initiator.engine.last_sas());
println!("responder SAS: {:?}", responder.engine.last_sas());
println!("initiator state: {:?}", initiator.engine.state());
println!("responder state: {:?}", responder.engine.state());
}