#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
use zeroize::Zeroize;
use crate::classic::crypto_kx::{crypto_kx_client_session_keys, crypto_kx_server_session_keys};
use crate::constants::{
CRYPTO_KX_PUBLICKEYBYTES, CRYPTO_KX_SECRETKEYBYTES, CRYPTO_KX_SESSIONKEYBYTES,
};
use crate::error::Error;
use crate::types::*;
pub type SessionKey = StackByteArray<CRYPTO_KX_SESSIONKEYBYTES>;
pub type PublicKey = StackByteArray<CRYPTO_KX_PUBLICKEYBYTES>;
pub type SecretKey = StackByteArray<CRYPTO_KX_SECRETKEYBYTES>;
pub type KeyPair = crate::keypair::KeyPair<PublicKey, SecretKey>;
#[cfg_attr(
feature = "serde",
derive(Zeroize, Clone, Debug, Serialize, Deserialize)
)]
#[cfg_attr(not(feature = "serde"), derive(Zeroize, Clone, Debug))]
pub struct Session<SessionKey: ByteArray<CRYPTO_KX_SESSIONKEYBYTES>> {
rx_key: SessionKey,
tx_key: SessionKey,
}
pub type StackSession = Session<SessionKey>;
#[cfg(any(feature = "nightly", all(doc, not(doctest))))]
#[cfg_attr(all(feature = "nightly", doc), doc(cfg(feature = "nightly")))]
pub mod protected {
use super::*;
pub use crate::keypair::protected::*;
pub use crate::protected::*;
pub use crate::types::*;
pub type SessionKey = HeapByteArray<CRYPTO_KX_SESSIONKEYBYTES>;
pub type PublicKey = HeapByteArray<CRYPTO_KX_PUBLICKEYBYTES>;
pub type SecretKey = HeapByteArray<CRYPTO_KX_SECRETKEYBYTES>;
pub type LockedKeyPair = crate::keypair::KeyPair<Locked<PublicKey>, Locked<SecretKey>>;
pub type LockedROKeyPair = crate::keypair::KeyPair<LockedRO<PublicKey>, LockedRO<SecretKey>>;
pub type LockedSession = Session<Locked<SessionKey>>;
}
impl<SessionKey: NewByteArray<CRYPTO_KX_SESSIONKEYBYTES>> Session<SessionKey> {
pub fn new_client<
PublicKey: ByteArray<CRYPTO_KX_PUBLICKEYBYTES>,
SecretKey: ByteArray<CRYPTO_KX_SECRETKEYBYTES>,
>(
client_keypair: &crate::keypair::KeyPair<PublicKey, SecretKey>,
server_public_key: &PublicKey,
) -> Result<Self, Error> {
let mut rx_key = SessionKey::new_byte_array();
let mut tx_key = SessionKey::new_byte_array();
crypto_kx_client_session_keys(
rx_key.as_mut_array(),
tx_key.as_mut_array(),
client_keypair.public_key.as_array(),
client_keypair.secret_key.as_array(),
server_public_key.as_array(),
)?;
Ok(Self { rx_key, tx_key })
}
pub fn new_server<
PublicKey: ByteArray<CRYPTO_KX_PUBLICKEYBYTES>,
SecretKey: ByteArray<CRYPTO_KX_SECRETKEYBYTES>,
>(
server_keypair: &crate::keypair::KeyPair<PublicKey, SecretKey>,
client_public_key: &PublicKey,
) -> Result<Self, Error> {
let mut rx_key = SessionKey::new_byte_array();
let mut tx_key = SessionKey::new_byte_array();
crypto_kx_server_session_keys(
rx_key.as_mut_array(),
tx_key.as_mut_array(),
server_keypair.public_key.as_array(),
server_keypair.secret_key.as_array(),
client_public_key.as_array(),
)?;
Ok(Self { rx_key, tx_key })
}
}
impl Session<SessionKey> {
pub fn new_client_with_defaults<
PublicKey: ByteArray<CRYPTO_KX_PUBLICKEYBYTES>,
SecretKey: ByteArray<CRYPTO_KX_SECRETKEYBYTES>,
>(
client_keypair: &crate::keypair::KeyPair<PublicKey, SecretKey>,
server_public_key: &PublicKey,
) -> Result<Self, Error> {
Self::new_client(client_keypair, server_public_key)
}
pub fn new_server_with_defaults<
PublicKey: ByteArray<CRYPTO_KX_PUBLICKEYBYTES>,
SecretKey: ByteArray<CRYPTO_KX_SECRETKEYBYTES>,
>(
server_keypair: &crate::keypair::KeyPair<PublicKey, SecretKey>,
client_public_key: &PublicKey,
) -> Result<Self, Error> {
Self::new_server(server_keypair, client_public_key)
}
}
impl<SessionKey: ByteArray<CRYPTO_KX_SESSIONKEYBYTES>> Session<SessionKey> {
pub fn into_parts(self) -> (SessionKey, SessionKey) {
(self.rx_key, self.tx_key)
}
#[inline]
pub fn rx_as_slice(&self) -> &[u8] {
self.rx_key.as_slice()
}
#[inline]
pub fn tx_as_slice(&self) -> &[u8] {
self.tx_key.as_slice()
}
#[inline]
pub fn rx_as_array(&self) -> &[u8; CRYPTO_KX_SESSIONKEYBYTES] {
self.rx_key.as_array()
}
#[inline]
pub fn tx_as_array(&self) -> &[u8; CRYPTO_KX_SESSIONKEYBYTES] {
self.tx_key.as_array()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_kx() {
let client_keypair = KeyPair::gen();
let server_keypair = KeyPair::gen();
let client_session_keys =
Session::new_client_with_defaults(&client_keypair, &server_keypair.public_key)
.expect("compute client failed");
let server_session_keys =
Session::new_server_with_defaults(&server_keypair, &client_keypair.public_key)
.expect("compute client failed");
let (client_rx, client_tx) = client_session_keys.into_parts();
let (server_rx, server_tx) = server_session_keys.into_parts();
assert_eq!(client_rx, server_tx);
assert_eq!(client_tx, server_rx);
}
}