use crate::ffi;
pub const PUBLICKEYBYTES: usize = ffi::crypto_kx_PUBLICKEYBYTES as usize;
pub const SECRETKEYBYTES: usize = ffi::crypto_kx_SECRETKEYBYTES as usize;
pub const SEEDBYTES: usize = ffi::crypto_kx_SEEDBYTES as usize;
pub const SESSIONKEYBYTES: usize = ffi::crypto_kx_SESSIONKEYBYTES as usize;
new_type! {
public PublicKey(PUBLICKEYBYTES);
}
new_type! {
secret SecretKey(SECRETKEYBYTES);
}
new_type! {
secret Seed(SEEDBYTES);
}
new_type! {
secret SessionKey(SESSIONKEYBYTES);
}
pub fn gen_keypair() -> (PublicKey, SecretKey) {
unsafe {
let mut pk = [0u8; PUBLICKEYBYTES];
let mut sk = [0u8; SECRETKEYBYTES];
let _ = ffi::crypto_kx_keypair(pk.as_mut_ptr(), sk.as_mut_ptr());
(PublicKey(pk), SecretKey(sk))
}
}
pub fn keypair_from_seed(&Seed(ref seed): &Seed) -> (PublicKey, SecretKey) {
unsafe {
let mut pk = [0u8; PUBLICKEYBYTES];
let mut sk = [0u8; SECRETKEYBYTES];
let _ = ffi::crypto_kx_seed_keypair(pk.as_mut_ptr(), sk.as_mut_ptr(), seed.as_ptr());
(PublicKey(pk), SecretKey(sk))
}
}
pub fn server_session_keys(
&PublicKey(ref server_pk): &PublicKey,
&SecretKey(ref server_sk): &SecretKey,
&PublicKey(ref client_pk): &PublicKey,
) -> Result<(SessionKey, SessionKey), ()> {
unsafe {
let mut rx = [0u8; SESSIONKEYBYTES];
let mut tx = [0u8; SESSIONKEYBYTES];
let r = ffi::crypto_kx_server_session_keys(
rx.as_mut_ptr(),
tx.as_mut_ptr(),
server_pk.as_ptr(),
server_sk.as_ptr(),
client_pk.as_ptr(),
);
if r != 0 {
Err(())
} else {
Ok((SessionKey(rx), SessionKey(tx)))
}
}
}
pub fn client_session_keys(
&PublicKey(ref client_pk): &PublicKey,
&SecretKey(ref client_sk): &SecretKey,
&PublicKey(ref server_pk): &PublicKey,
) -> Result<(SessionKey, SessionKey), ()> {
unsafe {
let mut rx = [0u8; SESSIONKEYBYTES];
let mut tx = [0u8; SESSIONKEYBYTES];
let r = ffi::crypto_kx_client_session_keys(
rx.as_mut_ptr(),
tx.as_mut_ptr(),
client_pk.as_ptr(),
client_sk.as_ptr(),
server_pk.as_ptr(),
);
if r != 0 {
Err(())
} else {
Ok((SessionKey(rx), SessionKey(tx)))
}
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_kx() {
unwrap!(crate::init());
let (client_pk, client_sk) = gen_keypair();
let (server_pk, server_sk) = gen_keypair();
assert!(client_pk != server_pk);
assert!(client_sk != server_sk);
let (client_rx, client_tx) =
unwrap!(client_session_keys(&client_pk, &client_sk, &server_pk));
let (server_rx, server_tx) =
unwrap!(server_session_keys(&server_pk, &server_sk, &client_pk));
assert!(client_rx == server_tx);
assert!(client_tx == server_rx);
}
#[test]
fn test_kx_non_acceptable_keys() {
unwrap!(crate::init());
let (client_pk, client_sk) = gen_keypair();
let (server_pk, server_sk) = gen_keypair();
let fake_client_pk = PublicKey([0u8; PUBLICKEYBYTES]);
let fake_server_pk = PublicKey([0u8; PUBLICKEYBYTES]);
assert!(client_session_keys(&client_pk, &client_sk, &fake_server_pk) == Err(()));
assert!(server_session_keys(&server_pk, &server_sk, &fake_client_pk) == Err(()));
}
#[test]
#[rustfmt::skip]
fn test_vectors() {
unwrap!(crate::init());
let small_order_p = PublicKey([
0xe0, 0xeb, 0x7a, 0x7c, 0x3b, 0x41, 0xb8, 0xae, 0x16, 0x56, 0xe3, 0xfa, 0xf1, 0x9f,
0xc4, 0x6a, 0xda, 0x09, 0x8d, 0xeb, 0x9c, 0x32, 0xb1, 0xfd, 0x86, 0x62, 0x05, 0x16,
0x5f, 0x49, 0xb8, 0x00]);
let mut seed = [0u8; SEEDBYTES];
for (i, elt) in seed.iter_mut().enumerate() {
*elt = i as u8;
}
let mut seed = Seed(seed);
let (mut client_pk, client_sk) = keypair_from_seed(&seed);
let client_pk_expected = PublicKey([
0x0e, 0x02, 0x16, 0x22, 0x3f, 0x14, 0x71, 0x43, 0xd3, 0x26, 0x15, 0xa9, 0x11, 0x89,
0xc2, 0x88, 0xc1, 0x72, 0x8c, 0xba, 0x3c, 0xc5, 0xf9, 0xf6, 0x21, 0xb1, 0x02, 0x6e,
0x03, 0xd8, 0x31, 0x29]);
assert_eq!(client_pk, client_pk_expected);
let client_sk_expected = SecretKey([
0xcb, 0x2f, 0x51, 0x60, 0xfc, 0x1f, 0x7e, 0x05, 0xa5, 0x5e, 0xf4, 0x9d, 0x34, 0x0b,
0x48, 0xda, 0x2e, 0x5a, 0x78, 0x09, 0x9d, 0x53, 0x39, 0x33, 0x51, 0xcd, 0x57, 0x9d,
0xd4, 0x25, 0x03, 0xd6]);
assert_eq!(client_sk, client_sk_expected);
let (server_pk, server_sk) = gen_keypair();
assert_eq!(
client_session_keys(&client_pk, &client_sk, &small_order_p),
Err(())
);
let (client_rx, client_tx) = unwrap!(client_session_keys(&client_pk, &client_sk, &server_pk)
);
assert_eq!(
server_session_keys(&server_pk, &server_sk, &small_order_p),
Err(())
);
let _ = unwrap!(server_session_keys(&server_pk, &server_sk, &client_pk));
client_pk.0[0] += 1;
let (server_rx, server_tx) = unwrap!(server_session_keys(&server_pk, &server_sk, &client_pk));
assert_ne!(server_rx.0, client_tx.0);
assert_ne!(server_tx.0, client_rx.0);
let (client_pk, _) = gen_keypair();
let (server_rx, server_tx) = unwrap!(server_session_keys(&server_pk, &server_sk, &client_pk));
assert_ne!(server_rx.0, client_tx.0);
assert_ne!(server_tx.0, client_rx.0);
let (client_pk, client_sk) = keypair_from_seed(&seed);
seed.0[0] += 1;
let (server_pk, server_sk) = keypair_from_seed(&seed);
let (server_rx, server_tx) = unwrap!(server_session_keys(&server_pk, &server_sk, &client_pk));
let server_rx_expected = SessionKey([
0x62, 0xc8, 0xf4, 0xfa, 0x81, 0x80, 0x0a, 0xbd, 0x05, 0x77, 0xd9, 0x99, 0x18, 0xd1,
0x29, 0xb6, 0x5d, 0xeb, 0x78, 0x9a, 0xf8, 0xc8, 0x35, 0x1f, 0x39, 0x1f, 0xeb, 0x0c,
0xbf, 0x23, 0x86, 0x04]);
let server_tx_expected = SessionKey([
0x74, 0x95, 0x19, 0xc6, 0x80, 0x59, 0xbc, 0xe6, 0x9f, 0x7c, 0xfc, 0xc7, 0xb3, 0x87,
0xa3, 0xde, 0x1a, 0x1e, 0x82, 0x37, 0xd1, 0x10, 0x99, 0x13, 0x23, 0xbf, 0x62, 0x87,
0x01, 0x15, 0x73, 0x1a]);
assert_eq!(server_rx, server_rx_expected);
assert_eq!(server_tx, server_tx_expected);
let (client_rx, client_tx) = unwrap!(client_session_keys(&client_pk, &client_sk, &server_pk));
let client_rx_expected = SessionKey([
0x74, 0x95, 0x19, 0xc6, 0x80, 0x59, 0xbc, 0xe6, 0x9f, 0x7c, 0xfc, 0xc7, 0xb3, 0x87,
0xa3, 0xde, 0x1a, 0x1e, 0x82, 0x37, 0xd1, 0x10, 0x99, 0x13, 0x23, 0xbf, 0x62, 0x87,
0x01, 0x15, 0x73, 0x1a]);
let client_tx_expected = SessionKey([
0x62, 0xc8, 0xf4, 0xfa, 0x81, 0x80, 0x0a, 0xbd, 0x05, 0x77, 0xd9, 0x99, 0x18, 0xd1,
0x29, 0xb6, 0x5d, 0xeb, 0x78, 0x9a, 0xf8, 0xc8, 0x35, 0x1f, 0x39, 0x1f, 0xeb, 0x0c,
0xbf, 0x23, 0x86, 0x04]);
assert_eq!(client_rx, client_rx_expected);
assert_eq!(client_tx, client_tx_expected);
}
}