-
-
Notifications
You must be signed in to change notification settings - Fork 119
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This PR addresses issues related to connecting to legacy Cisco devices with no upgrade path (similar to issue #277). Changes Introduced • Refactored cipher/mod.rs: Make room to be able to implement CBC crypto support. • Updated cipher/block.rs: To provide an interface compatible with both streaming ciphers and CBC. • General Cipher Updates: Light modifications to other ciphers for compatibility with the new interface. Context I had trouble connecting to older Cisco devices which posed challenges due to their outdated cryptographic support. --------- Co-authored-by: Eugene <[email protected]>
- Loading branch information
Showing
8 changed files
with
153 additions
and
29 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,5 @@ | ||
# Russh | ||
|
||
[![Rust](https://github.com/warp-tech/russh/actions/workflows/rust.yml/badge.svg)](https://github.com/warp-tech/russh/actions/workflows/rust.yml) <!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section --> | ||
[![All Contributors](https://img.shields.io/badge/all_contributors-34-orange.svg?style=flat-square)](#contributors-) | ||
<!-- ALL-CONTRIBUTORS-BADGE:END --> | ||
|
@@ -22,6 +23,9 @@ This is a fork of [Thrussh](https://nest.pijul.com/pijul/thrussh) by Pierre-Éti | |
* `aes256-ctr` ✨ | ||
* `aes192-ctr` ✨ | ||
* `aes128-ctr` ✨ | ||
* `aes256-cbc` ✨ | ||
* `aes192-cbc` ✨ | ||
* `aes128-cbc` ✨ | ||
* Key exchanges: | ||
* `[email protected]` | ||
* `diffie-hellman-group1-sha1` ✨ | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
use aes::cipher::{ | ||
BlockCipher, BlockDecrypt, BlockDecryptMut, BlockEncrypt, BlockEncryptMut, InnerIvInit, Iv, | ||
IvSizeUser, | ||
}; | ||
use cbc::{Decryptor, Encryptor}; | ||
use digest::crypto_common::InnerUser; | ||
use generic_array::GenericArray; | ||
|
||
use super::block::BlockStreamCipher; | ||
|
||
pub struct CbcWrapper<C: BlockEncrypt + BlockCipher + BlockDecrypt> { | ||
encryptor: Encryptor<C>, | ||
decryptor: Decryptor<C>, | ||
} | ||
|
||
impl<C: BlockEncrypt + BlockCipher + BlockDecrypt> InnerUser for CbcWrapper<C> { | ||
type Inner = C; | ||
} | ||
|
||
impl<C: BlockEncrypt + BlockCipher + BlockDecrypt> IvSizeUser for CbcWrapper<C> { | ||
type IvSize = C::BlockSize; | ||
} | ||
|
||
impl<C: BlockEncrypt + BlockCipher + BlockDecrypt> BlockStreamCipher for CbcWrapper<C> { | ||
fn encrypt_data(&mut self, data: &mut [u8]) { | ||
for chunk in data.chunks_exact_mut(C::block_size()) { | ||
let mut block: GenericArray<u8, _> = GenericArray::clone_from_slice(chunk); | ||
self.encryptor.encrypt_block_mut(&mut block); | ||
chunk.clone_from_slice(&block); | ||
} | ||
} | ||
|
||
fn decrypt_data(&mut self, data: &mut [u8]) { | ||
for chunk in data.chunks_exact_mut(C::block_size()) { | ||
let mut block = GenericArray::clone_from_slice(chunk); | ||
self.decryptor.decrypt_block_mut(&mut block); | ||
chunk.clone_from_slice(&block); | ||
} | ||
} | ||
} | ||
|
||
impl<C: BlockEncrypt + BlockCipher + BlockDecrypt + Clone> InnerIvInit for CbcWrapper<C> | ||
where | ||
C: BlockEncryptMut + BlockCipher, | ||
{ | ||
#[inline] | ||
fn inner_iv_init(cipher: C, iv: &Iv<Self>) -> Self { | ||
Self { | ||
encryptor: Encryptor::inner_iv_init(cipher.clone(), iv), | ||
decryptor: Decryptor::inner_iv_init(cipher, iv), | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -21,6 +21,7 @@ use std::num::Wrapping; | |
|
||
use aes::{Aes128, Aes192, Aes256}; | ||
use byteorder::{BigEndian, ByteOrder}; | ||
use cbc::CbcWrapper; | ||
use ctr::Ctr128BE; | ||
use log::debug; | ||
use once_cell::sync::Lazy; | ||
|
@@ -31,9 +32,11 @@ use crate::sshbuffer::SSHBuffer; | |
use crate::Error; | ||
|
||
pub(crate) mod block; | ||
pub(crate) mod cbc; | ||
pub(crate) mod chacha20poly1305; | ||
pub(crate) mod clear; | ||
pub(crate) mod gcm; | ||
|
||
use block::SshBlockCipher; | ||
use chacha20poly1305::SshChacha20Poly1305Cipher; | ||
use clear::Clear; | ||
|
@@ -69,6 +72,12 @@ pub const CLEAR: Name = Name("clear"); | |
pub const AES_128_CTR: Name = Name("aes128-ctr"); | ||
/// `aes192-ctr` | ||
pub const AES_192_CTR: Name = Name("aes192-ctr"); | ||
/// `aes128-cbc` | ||
pub const AES_128_CBC: Name = Name("aes128-cbc"); | ||
/// `aes192-cbc` | ||
pub const AES_192_CBC: Name = Name("aes192-cbc"); | ||
/// `aes256-cbc` | ||
pub const AES_256_CBC: Name = Name("aes256-cbc"); | ||
/// `aes256-ctr` | ||
pub const AES_256_CTR: Name = Name("aes256-ctr"); | ||
/// `[email protected]` | ||
|
@@ -83,6 +92,9 @@ static _AES_128_CTR: SshBlockCipher<Ctr128BE<Aes128>> = SshBlockCipher(PhantomDa | |
static _AES_192_CTR: SshBlockCipher<Ctr128BE<Aes192>> = SshBlockCipher(PhantomData); | ||
static _AES_256_CTR: SshBlockCipher<Ctr128BE<Aes256>> = SshBlockCipher(PhantomData); | ||
static _AES_256_GCM: GcmCipher = GcmCipher {}; | ||
static _AES_128_CBC: SshBlockCipher<CbcWrapper<Aes128>> = SshBlockCipher(PhantomData); | ||
static _AES_192_CBC: SshBlockCipher<CbcWrapper<Aes192>> = SshBlockCipher(PhantomData); | ||
static _AES_256_CBC: SshBlockCipher<CbcWrapper<Aes256>> = SshBlockCipher(PhantomData); | ||
static _CHACHA20_POLY1305: SshChacha20Poly1305Cipher = SshChacha20Poly1305Cipher {}; | ||
|
||
pub(crate) static CIPHERS: Lazy<HashMap<&'static Name, &(dyn Cipher + Send + Sync)>> = | ||
|
@@ -94,6 +106,9 @@ pub(crate) static CIPHERS: Lazy<HashMap<&'static Name, &(dyn Cipher + Send + Syn | |
h.insert(&AES_192_CTR, &_AES_192_CTR); | ||
h.insert(&AES_256_CTR, &_AES_256_CTR); | ||
h.insert(&AES_256_GCM, &_AES_256_GCM); | ||
h.insert(&AES_128_CBC, &_AES_128_CBC); | ||
h.insert(&AES_192_CBC, &_AES_192_CBC); | ||
h.insert(&AES_256_CBC, &_AES_256_CBC); | ||
h.insert(&CHACHA20_POLY1305, &_CHACHA20_POLY1305); | ||
h | ||
}); | ||
|
@@ -118,7 +133,11 @@ impl Debug for CipherPair { | |
} | ||
|
||
pub(crate) trait OpeningKey { | ||
fn decrypt_packet_length(&self, seqn: u32, encrypted_packet_length: [u8; 4]) -> [u8; 4]; | ||
fn packet_length_to_read_for_block_length(&self) -> usize { | ||
4 | ||
} | ||
|
||
fn decrypt_packet_length(&self, seqn: u32, encrypted_packet_length: &[u8]) -> [u8; 4]; | ||
|
||
fn tag_len(&self) -> usize; | ||
|
||
|
@@ -182,15 +201,16 @@ pub(crate) async fn read<'a, R: AsyncRead + Unpin>( | |
cipher: &'a mut (dyn OpeningKey + Send), | ||
) -> Result<usize, Error> { | ||
if buffer.len == 0 { | ||
let mut len = [0; 4]; | ||
let mut len = vec![0; cipher.packet_length_to_read_for_block_length()]; | ||
|
||
stream.read_exact(&mut len).await?; | ||
debug!("reading, len = {:?}", len); | ||
{ | ||
let seqn = buffer.seqn.0; | ||
buffer.buffer.clear(); | ||
buffer.buffer.extend(&len); | ||
debug!("reading, seqn = {:?}", seqn); | ||
let len = cipher.decrypt_packet_length(seqn, len); | ||
let len = cipher.decrypt_packet_length(seqn, &len); | ||
buffer.len = BigEndian::read_u32(&len) as usize + cipher.tag_len(); | ||
debug!("reading, clear len = {:?}", buffer.len); | ||
} | ||
|
@@ -199,7 +219,9 @@ pub(crate) async fn read<'a, R: AsyncRead + Unpin>( | |
buffer.buffer.resize(buffer.len + 4); | ||
debug!("read_exact {:?}", buffer.len + 4); | ||
#[allow(clippy::indexing_slicing)] // length checked | ||
stream.read_exact(&mut buffer.buffer[4..]).await?; | ||
stream | ||
.read_exact(&mut buffer.buffer[cipher.packet_length_to_read_for_block_length()..]) | ||
.await?; | ||
debug!("read_exact done"); | ||
let seqn = buffer.seqn.0; | ||
let ciphertext_len = buffer.buffer.len() - cipher.tag_len(); | ||
|