use aucpace::client::{AuCPaceClientPreAug, AuCPaceClientRecvServerKey};
use aucpace::server::{AuCPaceServerAugLayer, AuCPaceServerRecvClientKey};
use aucpace::{
Client, ClientMessage, Database, Error, PartialAugDatabase, Result, Server, ServerMessage,
};
use curve25519_dalek::{RistrettoPoint, Scalar};
use password_hash::{ParamsString, SaltString};
use rand_core::OsRng;
use scrypt::{Params, Scrypt};
use sha2::Sha512;
const USERNAME: &'static [u8] = b"jlpicard_1701";
const PASSWORD: &'static [u8] = b"g04tEd_c4pT41N";
const CI: &[u8] = b"test_channel_identifier";
const PRE_SSID: &[u8] = b"bestest_ssid_ever_i_promise";
const K1: usize = 16;
#[derive(Debug, Default)]
struct SingleUserDatabase {
user: Option<Vec<u8>>,
data: Option<(RistrettoPoint, SaltString, ParamsString)>,
long_term_keypair: Option<(Scalar, RistrettoPoint)>,
}
impl Database for SingleUserDatabase {
type PasswordVerifier = RistrettoPoint;
fn lookup_verifier(
&self,
username: &[u8],
) -> Option<(Self::PasswordVerifier, SaltString, ParamsString)> {
match &self.user {
Some(stored_username) if stored_username == username => self.data.clone(),
_ => None,
}
}
fn store_verifier(
&mut self,
username: &[u8],
salt: SaltString,
_uad: Option<&[u8]>,
verifier: Self::PasswordVerifier,
params: ParamsString,
) {
self.user = Some(username.to_vec());
self.data = Some((verifier, salt, params));
}
}
impl PartialAugDatabase for SingleUserDatabase {
type PrivateKey = Scalar;
type PublicKey = RistrettoPoint;
fn lookup_long_term_keypair(
&self,
username: &[u8],
) -> Option<(Self::PrivateKey, Self::PublicKey)> {
match &self.user {
Some(stored_user) if stored_user == username => self.long_term_keypair.clone(),
_ => None,
}
}
fn store_long_term_keypair(
&mut self,
username: &[u8],
priv_key: Self::PrivateKey,
pub_key: Self::PublicKey,
) -> Result<()> {
match &self.user {
Some(stored_user) if stored_user == username => {
self.long_term_keypair = Some((priv_key, pub_key));
Ok(())
}
_ => Err(Error::UserNotRegistered),
}
}
}
#[test]
fn test_key_agreement() -> Result<()> {
let (mut base_client, mut base_server, database) = init()?;
let (server, server_message) = base_server.begin();
let (client, client_message) = base_client.begin();
let server = if let ClientMessage::Nonce(client_nonce) = client_message {
server.agree_ssid(client_nonce)
} else {
panic!("Received invalid client message {:?}", client_message);
};
let client = if let ServerMessage::Nonce(server_nonce) = server_message {
client.agree_ssid(server_nonce)
} else {
panic!("Received invalid server message {:?}", server_message);
};
let (client, server, client_message, server_message) = test_core(client, server, &database)?;
let server = if let ClientMessage::PublicKey(client_pubkey) = client_message {
server.receive_client_pubkey(client_pubkey)?
} else {
panic!("Received invalid client message {:?}", client_message);
};
let (client, 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 (server_key, server_message) = if let ClientMessage::Authenticator(ca) = client_message {
server.receive_client_authenticator(ca)?
} else {
panic!("Received invalid client message {:?}", client_message);
};
let client_key = if let ServerMessage::Authenticator(sa) = server_message {
client.receive_server_authenticator(sa)?
} else {
panic!("Received invalid server message {:?}", server_message);
};
assert_eq!(client_key, server_key);
Ok(())
}
#[test]
fn test_key_agreement_implicit_auth() -> Result<()> {
let (mut base_client, mut base_server, database) = init()?;
let (server, server_message) = base_server.begin();
let (client, client_message) = base_client.begin();
let server = if let ClientMessage::Nonce(client_nonce) = client_message {
server.agree_ssid(client_nonce)
} else {
panic!("Received invalid client message {:?}", client_message);
};
let client = if let ServerMessage::Nonce(server_nonce) = server_message {
client.agree_ssid(server_nonce)
} else {
panic!("Received invalid server message {:?}", server_message);
};
let (client, server, client_message, server_message) = test_core(client, server, &database)?;
let server_key = if let ClientMessage::PublicKey(client_pubkey) = client_message {
server.implicit_auth(client_pubkey)?
} else {
panic!("Received invalid client message {:?}", client_message);
};
let client_key = if let ServerMessage::PublicKey(server_pubkey) = server_message {
client.implicit_auth(server_pubkey)?
} else {
panic!("Received invalid server message {:?}", server_message);
};
assert_eq!(client_key, server_key);
Ok(())
}
#[test]
fn test_key_agreement_prestablished_ssid() -> Result<()> {
let (mut base_client, mut base_server, database) = init()?;
let server = base_server.begin_prestablished_ssid(PRE_SSID)?;
let client = base_client.begin_prestablished_ssid(PRE_SSID)?;
let (client, server, client_message, server_message) = test_core(client, server, &database)?;
let server = if let ClientMessage::PublicKey(client_pubkey) = client_message {
server.receive_client_pubkey(client_pubkey)?
} else {
panic!("Received invalid client message {:?}", client_message);
};
let (client, 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 (server_key, server_message) = if let ClientMessage::Authenticator(ca) = client_message {
server.receive_client_authenticator(ca)?
} else {
panic!("Received invalid client message {:?}", client_message);
};
let client_key = if let ServerMessage::Authenticator(sa) = server_message {
client.receive_server_authenticator(sa)?
} else {
panic!("Received invalid server message {:?}", server_message);
};
assert_eq!(client_key, server_key);
Ok(())
}
#[test]
fn test_key_agreement_prestablished_ssid_implicit_auth() -> Result<()> {
let (mut base_client, mut base_server, database) = init()?;
let server = base_server.begin_prestablished_ssid(PRE_SSID)?;
let client = base_client.begin_prestablished_ssid(PRE_SSID)?;
let (client, server, client_message, server_message) = test_core(client, server, &database)?;
let server_key = if let ClientMessage::PublicKey(client_pubkey) = client_message {
server.implicit_auth(client_pubkey)?
} else {
panic!("Received invalid client message {:?}", client_message);
};
let client_key = if let ServerMessage::PublicKey(server_pubkey) = server_message {
client.implicit_auth(server_pubkey)?
} else {
panic!("Received invalid server message {:?}", server_message);
};
assert_eq!(client_key, server_key);
Ok(())
}
fn init() -> Result<(Client, Server, SingleUserDatabase)> {
let mut base_server = Server::new(OsRng);
let mut base_client = Client::new(OsRng);
let mut database: SingleUserDatabase = Default::default();
let params = Params::recommended();
let registration = base_client.register_alloc(USERNAME, PASSWORD, params, Scrypt)?;
if let ClientMessage::Registration {
username,
salt,
params,
verifier,
} = registration
{
database.store_verifier(username, salt, None, verifier, params);
let (private, public) = base_server.generate_long_term_keypair();
database.store_long_term_keypair(username, private, public)?;
}
Ok((base_client, base_server, database))
}
fn test_core(
client: AuCPaceClientPreAug<Sha512, Scrypt, K1>,
server: AuCPaceServerAugLayer<Sha512, K1>,
database: &SingleUserDatabase,
) -> Result<(
AuCPaceClientRecvServerKey<Sha512, K1>,
AuCPaceServerRecvClientKey<Sha512, K1>,
ClientMessage<K1>,
ServerMessage<K1>,
)> {
let (client, client_message) = client.start_augmentation(USERNAME, PASSWORD);
let (server, server_message) = if let ClientMessage::Username(username) = client_message {
server.generate_client_info_partial_aug(username, database, OsRng)
} else {
panic!("Received invalid client message {:?}", client_message);
};
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, Params::RECOMMENDED_LEN).unwrap()
};
client.generate_cpace_alloc(x_pub, &salt, params, Scrypt)?
} else {
panic!("Received invalid server message {:?}", server_message);
};
let (server, server_message) = server.generate_public_key(CI);
let (client, client_message) = client.generate_public_key(CI, &mut OsRng);
Ok((client, server, client_message, server_message))
}