#![no_std]
extern crate std;
use std::{println, time::Instant};
use aucpace::{Client, ClientMessage, Database, Result, Server, ServerMessage};
use curve25519_dalek::ristretto::RistrettoPoint;
use password_hash::{ParamsString, SaltString};
use rand_core::OsRng;
use scrypt::{Params, Scrypt};
macro_rules! send {
($buf:ident, $msg:ident) => {{
$buf.fill(0u8);
let serialised = postcard::to_slice(&$msg, &mut $buf).unwrap();
serialised.len()
}};
}
macro_rules! recv {
($buf:ident) => {{
postcard::from_bytes(&$buf).unwrap()
}};
}
fn main() -> Result<()> {
const USERNAME: &'static [u8] = b"adira.tal";
const PASSWORD: &'static [u8] = b"4d1rA_aND-Gr4Y_aRe_tH3-b3sT <3";
let mut base_server = Server::new(OsRng);
let mut base_client = Client::new(OsRng);
let mut database: SingleUserDatabase<100> = Default::default();
let start = Instant::now();
let params = Params::recommended();
let registration = base_client.register::<&[u8], 100>(USERNAME, PASSWORD, params, Scrypt)?;
if let ClientMessage::Registration {
username,
salt,
params,
verifier,
} = registration
{
database.store_verifier(username, salt, None, verifier, params);
}
println!(
"Registered `{}:{}` in {}ms",
core::str::from_utf8(USERNAME).unwrap(),
core::str::from_utf8(PASSWORD).unwrap(),
Instant::now().duration_since(start).as_millis()
);
let mut client_bytes_sent = 0;
let mut server_bytes_sent = 0;
let start = Instant::now();
let mut client_buf = [0u8; 1024];
let mut server_buf = [0u8; 1024];
let (client, message) = base_client.begin();
let bytes_sent = send!(client_buf, message);
client_bytes_sent += bytes_sent;
println!(
"[client] Sending message: ClientNonce, sent {} bytes",
bytes_sent
);
let mut client_message: ClientMessage<16> = recv!(client_buf);
let server = if let ClientMessage::Nonce(client_nonce) = client_message {
let (server, message) = base_server.begin();
let bytes_sent = send!(server_buf, message);
server_bytes_sent += bytes_sent;
println!(
"[server] Sending message: ServerNonce, sent {} bytes",
bytes_sent
);
server.agree_ssid(client_nonce)
} else {
panic!("Received invalid client message {:?}", client_message);
};
let mut server_message = recv!(server_buf);
let client = if let ServerMessage::Nonce(nonce) = server_message {
client.agree_ssid(nonce)
} else {
panic!("Received invalid client message {:?}", client_message);
};
let (client, message) = client.start_augmentation(USERNAME, PASSWORD);
let bytes_sent = send!(client_buf, message);
client_bytes_sent += bytes_sent;
println!(
"[client] Sending message: Username, sent {} bytes",
bytes_sent
);
client_message = recv!(client_buf);
let (server, message) = if let ClientMessage::Username(username) = client_message {
server.generate_client_info(username, &database, OsRng)
} else {
panic!("Received invalid client message {:?}", client_message);
};
let bytes_sent = send!(server_buf, message);
server_bytes_sent += bytes_sent;
println!(
"[server] Sending message: AugmentationInfo, sent {} bytes",
bytes_sent
);
server_message = recv!(server_buf);
let client = if let ServerMessage::AugmentationInfo {
x_pub,
salt,
pbkdf_params,
..
} = server_message
{
let params = {
let log_n = pbkdf_params.get_str("ln").unwrap().parse().unwrap();
let r = pbkdf_params.get_str("r").unwrap().parse().unwrap();
let p = pbkdf_params.get_str("p").unwrap().parse().unwrap();
Params::new(log_n, r, p, scrypt::Params::RECOMMENDED_LEN).unwrap()
};
client.generate_cpace::<&SaltString, 100>(x_pub, &salt, params, Scrypt)?
} else {
panic!("Received invalid server message {:?}", server_message);
};
const CI: &'static str = "channel_identifier";
let (server, message) = server.generate_public_key(CI);
let bytes_sent = send!(server_buf, message);
server_bytes_sent += bytes_sent;
println!(
"[server] Sending message: PublicKey, sent {} bytes",
bytes_sent
);
let (client, message) = client.generate_public_key(CI, &mut OsRng);
let bytes_sent = send!(client_buf, message);
client_bytes_sent += bytes_sent;
println!(
"[client] Sending message: PublicKey, sent {} bytes",
bytes_sent
);
client_message = recv!(client_buf);
let server = if let ClientMessage::PublicKey(client_pubkey) = client_message {
server.receive_client_pubkey(client_pubkey)?
} else {
panic!("Received invalid client message {:?}", client_message);
};
server_message = recv!(server_buf);
let (client, message) = if let ServerMessage::PublicKey(server_pubkey) = server_message {
client.receive_server_pubkey(server_pubkey)?
} else {
panic!("Received invalid server message {:?}", server_message);
};
let bytes_sent = send!(client_buf, message);
client_bytes_sent += bytes_sent;
println!(
"[client] Sending message: Authenticator, sent {} bytes",
bytes_sent
);
client_message = recv!(client_buf);
let server_key = if let ClientMessage::Authenticator(client_authenticator) = client_message {
let (key, message) = server.receive_client_authenticator(client_authenticator)?;
let bytes_sent = send!(server_buf, message);
server_bytes_sent += bytes_sent;
println!(
"[server] Sending message: Authenticator, sent {} bytes",
bytes_sent
);
key
} else {
panic!("Received invalid client message {:?}", client_message);
};
server_message = recv!(server_buf);
let client_key = if let ServerMessage::Authenticator(server_authenticator) = server_message {
client
.receive_server_authenticator(server_authenticator)
.unwrap()
} else {
panic!("Received invalid server message {:?}", server_message);
};
let end = Instant::now();
assert_eq!(client_key, server_key);
println!(
"Negotiation finished, both parties arrived at a key of: {:X}",
client_key
);
println!("Client sent {} bytes total", client_bytes_sent);
println!("Server sent {} bytes total", server_bytes_sent);
println!(
"The computation took {}ms",
end.duration_since(start).as_millis()
);
Ok(())
}
#[derive(Debug, Default)]
struct SingleUserDatabase<const USERSIZE: usize> {
user: Option<([u8; USERSIZE], usize)>,
data: Option<(RistrettoPoint, SaltString, ParamsString)>,
}
impl<const USERSIZE: usize> Database for SingleUserDatabase<USERSIZE> {
type PasswordVerifier = RistrettoPoint;
fn lookup_verifier(
&self,
username: &[u8],
) -> Option<(Self::PasswordVerifier, SaltString, ParamsString)> {
match self.user {
Some((ref stored_username, len)) if &stored_username[..len] == username => {
self.data.clone()
}
_ => None,
}
}
fn store_verifier(
&mut self,
username: &[u8],
salt: SaltString,
_uad: Option<&[u8]>,
verifier: Self::PasswordVerifier,
params: ParamsString,
) {
if username.len() <= USERSIZE {
let mut buf = [0u8; USERSIZE];
buf[..username.len()].copy_from_slice(username);
self.user = Some((buf, username.len()));
self.data = Some((verifier, salt, params));
}
}
}