@@ -34,9 +34,11 @@ fn new_cipher_from_slices<C: KeyIvInit>(k: &[u8], n: &[u8]) -> C {
3434 )
3535}
3636
37- pub struct SshBlockCipher < C : BlockStreamCipher + KeySizeUser + IvSizeUser > ( pub PhantomData < C > ) ;
37+ pub struct SshBlockCipher < C : BlockStreamCipher + PacketLengthProbe + KeySizeUser + IvSizeUser > (
38+ pub PhantomData < C > ,
39+ ) ;
3840
39- impl < C : BlockStreamCipher + KeySizeUser + IvSizeUser + KeyIvInit + Clone + Send + ' static >
41+ impl < C : BlockStreamCipher + PacketLengthProbe + KeySizeUser + IvSizeUser + KeyIvInit + Send + ' static >
4042 super :: Cipher for SshBlockCipher < C >
4143{
4244 fn key_len ( & self ) -> usize {
@@ -78,7 +80,7 @@ impl<C: BlockStreamCipher + KeySizeUser + IvSizeUser + KeyIvInit + Clone + Send
7880 }
7981}
8082
81- pub struct OpeningKey < C : BlockStreamCipher > {
83+ pub struct OpeningKey < C : BlockStreamCipher + PacketLengthProbe > {
8284 pub ( crate ) cipher : C ,
8385 pub ( crate ) mac : Box < dyn Mac + Send > ,
8486}
@@ -88,7 +90,9 @@ pub struct SealingKey<C: BlockStreamCipher> {
8890 pub ( crate ) mac : Box < dyn Mac + Send > ,
8991}
9092
91- impl < C : BlockStreamCipher + KeySizeUser + IvSizeUser + Clone > super :: OpeningKey for OpeningKey < C > {
93+ impl < C : BlockStreamCipher + PacketLengthProbe + KeySizeUser + IvSizeUser > super :: OpeningKey
94+ for OpeningKey < C >
95+ {
9296 fn packet_length_to_read_for_block_length ( & self ) -> usize {
9397 16
9498 }
@@ -108,9 +112,7 @@ impl<C: BlockStreamCipher + KeySizeUser + IvSizeUser + Clone> super::OpeningKey
108112 #[ allow( clippy:: unwrap_used, clippy:: indexing_slicing) ]
109113 encrypted_packet_length[ ..4 ] . try_into ( ) . unwrap ( )
110114 } else {
111- let mut cipher = self . cipher . clone ( ) ;
112-
113- cipher. decrypt_data ( & mut first_block) ;
115+ self . cipher . decrypt_packet_length_block ( & mut first_block) ;
114116
115117 // Fine because of self.packet_length_to_read_for_block_length()
116118 #[ allow( clippy:: unwrap_used, clippy:: indexing_slicing) ]
@@ -212,6 +214,10 @@ pub trait BlockStreamCipher {
212214 fn decrypt_data ( & mut self , data : & mut [ u8 ] ) ;
213215}
214216
217+ pub ( crate ) trait PacketLengthProbe {
218+ fn decrypt_packet_length_block ( & self , first_block : & mut [ u8 ; 16 ] ) ;
219+ }
220+
215221impl < T : StreamCipher > BlockStreamCipher for T {
216222 fn encrypt_data ( & mut self , data : & mut [ u8 ] ) {
217223 self . apply_keystream ( data) ;
@@ -222,16 +228,48 @@ impl<T: StreamCipher> BlockStreamCipher for T {
222228 }
223229}
224230
231+ impl < T : StreamCipher + Clone > PacketLengthProbe for T {
232+ fn decrypt_packet_length_block ( & self , first_block : & mut [ u8 ; 16 ] ) {
233+ let mut cipher = self . clone ( ) ;
234+ cipher. apply_keystream ( first_block) ;
235+ }
236+ }
237+
225238#[ cfg( test) ]
226239mod tests {
240+ use aes:: cipher:: KeyIvInit ;
241+ use aes:: cipher:: StreamCipher ;
242+ use aes:: Aes128 ;
227243 use aes:: cipher:: { IvSizeUser , KeySizeUser } ;
244+ use ctr:: Ctr128BE ;
228245 use digest:: typenum:: U16 ;
229246 use tokio:: io:: AsyncWriteExt ;
230247
231- use super :: { BlockStreamCipher , OpeningKey } ;
248+ use super :: { BlockStreamCipher , OpeningKey , PacketLengthProbe } ;
232249 use crate :: mac:: MacAlgorithm ;
233250 use crate :: sshbuffer:: SSHBuffer ;
234251
252+ #[ test]
253+ fn stream_cipher_probe_does_not_advance_cipher_state ( ) {
254+ let plaintext = * b"0123456789ABCDEF" ;
255+ let key = fixture_bytes :: < 16 > ( 7 ) ;
256+ let iv = fixture_bytes :: < 16 > ( 3 ) ;
257+
258+ let mut encryptor = Ctr128BE :: < Aes128 > :: new ( & key. into ( ) , & iv. into ( ) ) ;
259+ let mut ciphertext = plaintext;
260+ encryptor. apply_keystream ( & mut ciphertext) ;
261+
262+ let cipher = Ctr128BE :: < Aes128 > :: new ( & key. into ( ) , & iv. into ( ) ) ;
263+ let mut probed_block = ciphertext;
264+ cipher. decrypt_packet_length_block ( & mut probed_block) ;
265+ assert_eq ! ( probed_block, plaintext) ;
266+
267+ let mut decrypted = ciphertext;
268+ let mut cipher_after_probe = cipher;
269+ cipher_after_probe. decrypt_data ( & mut decrypted) ;
270+ assert_eq ! ( decrypted, plaintext) ;
271+ }
272+
235273 #[ test]
236274 fn decrypt_packet_length_uses_independent_cipher_state ( ) -> std:: io:: Result < ( ) > {
237275 let runtime = tokio:: runtime:: Builder :: new_current_thread ( )
@@ -292,4 +330,20 @@ mod tests {
292330 }
293331 }
294332 }
333+
334+ impl PacketLengthProbe for OwnedStateCipher {
335+ fn decrypt_packet_length_block ( & self , first_block : & mut [ u8 ; 16 ] ) {
336+ if let Some ( prefix) = first_block. get_mut ( ..4 ) {
337+ prefix. copy_from_slice ( & [ 0 , 0 , 0 , 12 ] ) ;
338+ }
339+ }
340+ }
341+
342+ fn fixture_bytes < const N : usize > ( seed : u8 ) -> [ u8 ; N ] {
343+ let mut bytes = [ 0 ; N ] ;
344+ for ( i, byte) in bytes. iter_mut ( ) . enumerate ( ) {
345+ * byte = seed. wrapping_add ( i as u8 ) ;
346+ }
347+ bytes
348+ }
295349}
0 commit comments