askar_crypto/kdf/
ecdh_es.rs1use sha2::Sha256;
4use zeroize::Zeroize;
5
6use super::{
7 concat::{ConcatKDFHash, ConcatKDFParams},
8 KeyDerivation, KeyExchange,
9};
10use crate::error::Error;
11
12#[derive(Debug)]
14pub struct EcdhEs<'d, Key>
15where
16 Key: KeyExchange + ?Sized,
17{
18 ephem_key: &'d Key,
19 recip_key: &'d Key,
20 alg: &'d [u8],
21 apu: &'d [u8],
22 apv: &'d [u8],
23 receive: bool,
24}
25
26impl<'d, Key: KeyExchange + ?Sized> EcdhEs<'d, Key> {
27 pub fn new(
29 ephem_key: &'d Key,
30 recip_key: &'d Key,
31 alg: &'d [u8],
32 apu: &'d [u8],
33 apv: &'d [u8],
34 receive: bool,
35 ) -> Self {
36 Self {
37 ephem_key,
38 recip_key,
39 alg,
40 apu,
41 apv,
42 receive,
43 }
44 }
45}
46
47impl<Key: KeyExchange + ?Sized> KeyDerivation for EcdhEs<'_, Key> {
48 fn derive_key_bytes(&mut self, key_output: &mut [u8]) -> Result<(), Error> {
49 let output_len = key_output.len();
50 if output_len > 32 {
52 return Err(err_msg!(Unsupported, "Exceeded maximum output length"));
53 }
54 let mut kdf = ConcatKDFHash::<Sha256>::new();
55 kdf.start_pass();
56
57 if self.receive {
59 self.recip_key
60 .write_key_exchange(self.ephem_key, &mut kdf)?;
61 } else {
62 self.ephem_key
63 .write_key_exchange(self.recip_key, &mut kdf)?;
64 }
65
66 kdf.hash_params(ConcatKDFParams {
67 alg: self.alg,
68 apu: self.apu,
69 apv: self.apv,
70 pub_info: &((output_len as u32) * 8).to_be_bytes(), prv_info: &[],
72 });
73
74 let mut key = kdf.finish_pass();
75 key_output.copy_from_slice(&key[..output_len]);
76 key.zeroize();
77
78 Ok(())
79 }
80}
81
82#[cfg(test)]
83mod tests {
84 #[allow(unused_imports)]
85 use super::*;
86
87 #[cfg(feature = "ed25519")]
88 #[test]
89 fn expected_es_direct_output() {
92 use crate::alg::x25519::X25519KeyPair;
93 use crate::jwk::FromJwk;
94
95 let bob_pk = X25519KeyPair::from_jwk(
96 r#"{"kty":"OKP","crv":"X25519","kid":"Bob",
97 "x":"3p7bfXt9wbTTW2HC7OQ1Nz-DQ8hbeGdNrfx-FG-IK08"}"#,
98 )
99 .unwrap();
100 let ephem_sk = X25519KeyPair::from_jwk(
101 r#"{"kty":"OKP","crv":"X25519",
102 "d":"dwdtCnMYpX08FsFyUbJmRd9ML4frwJkqsXf7pR25LCo",
103 "x":"hSDwCYkwp1R0i33ctD73Wg2_Og0mOBr066SpjqqbTmo"}
104 "#,
105 )
106 .unwrap();
107
108 let xk = ephem_sk.key_exchange_bytes(&bob_pk).unwrap();
109 assert_eq!(
110 xk,
111 &hex!("4a5d9d5ba4ce2de1728e3bf480350f25e07e21c947d19e3376f09b3c1e161742")[..]
112 );
113
114 let mut key_output = [0u8; 32];
115
116 EcdhEs::new(&ephem_sk, &bob_pk, b"A256GCM", b"Alice", b"Bob", false)
117 .derive_key_bytes(&mut key_output)
118 .unwrap();
119
120 assert_eq!(
121 key_output,
122 hex!("2f3636918ddb57fe0b3569113f19c4b6c518c2843f8930f05db25cd55dee53c1")
123 );
124 }
125}