pakery_spake2plus/
transcript.rs1use alloc::vec::Vec;
4use zeroize::{Zeroize, ZeroizeOnDrop, Zeroizing};
5
6use pakery_core::crypto::{Hash, Kdf, Mac};
7use pakery_core::SharedSecret;
8
9use crate::ciphersuite::Spake2PlusCiphersuite;
10use crate::error::Spake2PlusError;
11
12#[derive(Zeroize, ZeroizeOnDrop)]
14pub struct Spake2PlusOutput {
15 #[zeroize(skip)]
17 pub session_key: SharedSecret,
18}
19
20pub(crate) struct KeySchedule {
24 pub confirm_p: Vec<u8>,
25 pub confirm_v: Vec<u8>,
26 pub session_key: SharedSecret,
27}
28
29impl Drop for KeySchedule {
30 fn drop(&mut self) {
31 self.confirm_p.zeroize();
32 self.confirm_v.zeroize();
33 }
35}
36
37pub(crate) fn derive_key_schedule<C: Spake2PlusCiphersuite>(
46 tt: &[u8],
47 share_p: &[u8],
48 share_v: &[u8],
49) -> Result<KeySchedule, Spake2PlusError> {
50 const { assert!(<C::Hash as pakery_core::crypto::Hash>::OUTPUT_SIZE >= C::NH) };
52 let k_main = Zeroizing::new(C::Hash::digest(tt));
53
54 let prk = C::Kdf::extract(&[], &k_main[..C::NH]);
56
57 let kc = C::Kdf::expand(&prk, b"ConfirmationKeys", 2 * C::NH)
59 .map_err(|_| Spake2PlusError::InternalError("KDF expand failed for ConfirmationKeys"))?;
60 let k_confirm_p = &kc[..C::NH];
61 let k_confirm_v = &kc[C::NH..2 * C::NH];
62
63 let mut k_shared = C::Kdf::expand(&prk, b"SharedKey", C::NH)
65 .map_err(|_| Spake2PlusError::InternalError("KDF expand failed for SharedKey"))?;
66
67 let confirm_v = C::Mac::mac(k_confirm_v, share_p)
70 .map_err(|_| Spake2PlusError::InternalError("MAC computation failed"))?;
71 let confirm_p = C::Mac::mac(k_confirm_p, share_v)
72 .map_err(|_| Spake2PlusError::InternalError("MAC computation failed"))?;
73
74 Ok(KeySchedule {
75 confirm_p,
76 confirm_v,
77 session_key: SharedSecret::new(core::mem::take(&mut *k_shared)),
78 })
79}