@@ -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
1966impl 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
215272impl 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
0 commit comments