Skip to content

Commit 587562f

Browse files
bjorn3djc
authored andcommitted
Add code to derive encryption keys
This doesn't yet implement the actual encryption/decryption yet.
1 parent 342f385 commit 587562f

File tree

2 files changed

+70
-7
lines changed

2 files changed

+70
-7
lines changed

src/key_exchange.rs

Lines changed: 69 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,54 @@ use crate::{
1414
Connection, Error,
1515
};
1616

17-
pub(crate) struct EcdhKeyExchange(());
17+
/// The raw hashes from which we will derive the crypto keys.
18+
#[expect(dead_code)] // FIXME implement encryption/decryption and MAC
19+
struct RawKeys {
20+
client_to_server: RawKeysOneWay,
21+
server_to_client: RawKeysOneWay,
22+
}
23+
24+
#[expect(dead_code)] // FIXME implement encryption/decryption and MAC
25+
struct RawKeysOneWay {
26+
initial_iv: digest::Digest,
27+
encryption_key: digest::Digest,
28+
integrity_key: digest::Digest,
29+
}
30+
31+
impl RawKeys {
32+
fn derive(
33+
shared_secret: Vec<u8>,
34+
exchange_hash: digest::Digest,
35+
session_id: &digest::Digest,
36+
) -> Self {
37+
let compute_key = |key: &str| {
38+
let mut context = digest::Context::new(&digest::SHA256);
39+
with_mpint_bytes(&shared_secret, |bytes| context.update(bytes));
40+
context.update(exchange_hash.as_ref());
41+
context.update(key.as_bytes());
42+
context.update(session_id.as_ref());
43+
context.finish()
44+
};
45+
46+
Self {
47+
client_to_server: RawKeysOneWay {
48+
initial_iv: compute_key("A"),
49+
encryption_key: compute_key("C"),
50+
integrity_key: compute_key("E"),
51+
},
52+
server_to_client: RawKeysOneWay {
53+
initial_iv: compute_key("A"),
54+
encryption_key: compute_key("C"),
55+
integrity_key: compute_key("E"),
56+
},
57+
}
58+
}
59+
}
60+
61+
pub(crate) struct EcdhKeyExchange {
62+
/// The current session id or `None` if this is the initial key exchange.
63+
session_id: Option<digest::Digest>,
64+
}
1865

1966
impl EcdhKeyExchange {
2067
pub(crate) async fn advance(
@@ -89,8 +136,8 @@ impl EcdhKeyExchange {
89136

90137
with_mpint_bytes(&shared_secret, |bytes| exchange.update(bytes));
91138

92-
let hash = exchange.finish();
93-
let signature = conn.host_key.sign(hash.as_ref());
139+
let exchange_hash = exchange.finish();
140+
let signature = conn.host_key.sign(exchange_hash.as_ref());
94141
let key_exchange_reply = EcdhKeyExchangeReply {
95142
server_public_host_key: TaggedPublicKey {
96143
algorithm: PublicKeyAlgorithm::Ed25519,
@@ -117,6 +164,13 @@ impl EcdhKeyExchange {
117164
return Err(());
118165
}
119166

167+
// FIXME wait for and send newkey packet
168+
169+
// The first exchange hash is used as session id.
170+
let session_id = self.session_id.as_ref().unwrap_or(&exchange_hash);
171+
172+
RawKeys::derive(shared_secret, exchange_hash, session_id);
173+
120174
Ok(())
121175
}
122176
}
@@ -209,10 +263,17 @@ impl Encode for TaggedSignature<'_> {
209263
}
210264
}
211265

212-
#[derive(Debug, Default)]
213-
pub(crate) struct KeyExchange(());
266+
#[derive(Debug)]
267+
pub(crate) struct KeyExchange {
268+
/// The current session id or `None` if this is the initial key exchange.
269+
session_id: Option<digest::Digest>,
270+
}
214271

215272
impl KeyExchange {
273+
pub(crate) fn for_new_session() -> Self {
274+
Self { session_id: None }
275+
}
276+
216277
pub(crate) async fn advance(
217278
&self,
218279
exchange: &mut digest::Context,
@@ -288,7 +349,9 @@ impl KeyExchange {
288349
}
289350
conn.read_buf.truncate(rest);
290351

291-
Ok(EcdhKeyExchange(()))
352+
Ok(EcdhKeyExchange {
353+
session_id: self.session_id,
354+
})
292355
}
293356
}
294357

src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ impl VersionExchange {
108108
}
109109
conn.read_buf.truncate(rest);
110110

111-
Ok(KeyExchange::default())
111+
Ok(KeyExchange::for_new_session())
112112
}
113113
}
114114

0 commit comments

Comments
 (0)