use tls_codec::{SerializeBytes, TlsDeserialize, TlsSerialize, TlsSerializeBytes, TlsSize};
use crate::{
aead::{AEADKeyNonce, AeadType},
handshake::transcript::Transcript,
};
use super::SessionError as Error;
pub const SESSION_ID_LENGTH: usize = 32;
#[derive(TlsSerialize, TlsDeserialize, TlsSize)]
pub struct SessionKey {
pub(crate) identifier: [u8; SESSION_ID_LENGTH],
pub(crate) key: AEADKeyNonce,
}
const SESSION_KEY_INFO: &[u8] = b"session key id";
const SESSION_KEY_SALT: &[u8] = b"session key salt";
fn session_key_id(key: &AEADKeyNonce) -> Result<[u8; SESSION_ID_LENGTH], Error> {
let mut session_id = [0u8; SESSION_ID_LENGTH];
libcrux_hkdf::sha2_256::hkdf(
&mut session_id,
SESSION_KEY_SALT,
&SerializeBytes::tls_serialize(&key).map_err(Error::Serialize)?,
SESSION_KEY_INFO,
)
.map_err(|_| Error::CryptoError)?;
Ok(session_id)
}
pub(super) fn derive_session_key(
k2: AEADKeyNonce,
tx2: &Transcript,
aead_type: AeadType,
) -> Result<SessionKey, Error> {
#[derive(TlsSerializeBytes, TlsSize)]
struct SessionKeyInfo<'a> {
domain_separator: &'static [u8],
tx2: &'a Transcript,
}
const SESSION_KEY_LABEL: &[u8] = b"session key";
let key = AEADKeyNonce::new_expired(
&k2,
&SessionKeyInfo {
domain_separator: SESSION_KEY_LABEL,
tx2,
},
aead_type,
)?;
let identifier = session_key_id(&key)?;
Ok(SessionKey { key, identifier })
}
pub(super) fn derive_import_key(
k2: AEADKeyNonce,
psk: &[u8],
aead_type: AeadType,
) -> Result<AEADKeyNonce, Error> {
#[derive(TlsSerializeBytes, TlsSize)]
struct SessionImportInfo {
domain_separator: &'static [u8],
}
#[derive(TlsSerializeBytes, TlsSize)]
struct SessionImportIkm<'a> {
old_session_key: &'a AEADKeyNonce,
psk: &'a [u8],
}
const SESSION_IMPORT_LABEL: &[u8] = b"secret import";
AEADKeyNonce::new_expired(
&SessionImportIkm {
old_session_key: &k2,
psk,
},
&SessionImportInfo {
domain_separator: SESSION_IMPORT_LABEL,
},
aead_type,
)
.map_err(|_| Error::Import)
}