Pure-Rust asynchronous SSH library, both client and server

#25 Alternative KEX algorithms

Opened by mcronce on February 17, 2021
mcronce on February 17, 2021

Hey guys,

Awesome crate. I’m in the process of implementing an SFTP server with it, and it’s been great to use so far.

The problem I’m trying to run into is supporting a piece of hardware with, apparently, super limited security (surprise surprise, right?) - a Brother ADS-2700W scanner. When I try to connect to the server from the scanner, with debug logging enabled, I get the following:

[2021-02-18T03:33:55Z DEBUG thrussh::negotiation] Could not find common kex algorithm, other side only supports Ok("diffie-hellman-group14-sha1,diffie-hellman-group-exchange-sha1,diffie-hellman-group1-sha1"), we only support [Name("curve25519-sha256@libssh.org")]

I’m interested in adding support for one of these to thrussh. From reading https://tools.ietf.org/id/draft-ietf-curdle-ssh-kex-sha2-09.html#rfc.section.3, it sounds like of these, diffie-hellman-group14-sha1 is the most secure (or, maybe, “least insecure” is a more accurate way to put it :) )

I was hoping you might be able to provide some direction on how best to get started with implementation.

Thanks!

pmeunier on February 18, 2021

This is a super interesting project. There’s only one key exchange algorithm implemented at the moment, living in the kex module in crate thrussh.

I believe you would need to make it generic, by turning the current methods implemented on Algorithm into a trait: add a file kex/mod.rs with the trait, and move the current implementation to kex/curve25519.rs. You should then be ready to add your algorithm.

If don’t know whether that algorithm is implemented in an external crate. If it is in OpenSSL, try to get it from there if you can. Else, you’ll have to implement it yourself, in which case a pure Rust implementation (preferably in an external crate) seems to be as secure as any other implementation of that algorithm :)

In general, try to avoid making functions generic, and always prefer dynamic trait pointers (of the form fn f(a: &dyn Algorithm) rather than fn f<A: Algorithm>(a: &A)). The goal of doing this is to avoid code bloat (in the assembly). This strategy comes at the expense of inlining and performance, but this kind of advanced optimisation isn’t the goal of this crate, memory allocations and IO matter much more, and clean, readable code are usually very helpful for that.

Feel free to ask for more help if you need.

mcronce on February 19, 2021

Thanks! I think I’m off and running…just adding the kex and key names is sufficient to get kex as far as negotiating a cipher. (I had to add pub const DH14SHA1: Name = Name("diffie-hellman-group14-sha1"), but key::SSH_RSA already existed, just nedded to add it to Preferred.)

The most reasonable cipher the scanner supports is aes256cbc, so I’m attempting to implement that. It looks like openssl can do all the heavy lifting, just need to figure out how to make it work in the context of thrussh :)

I expect that with only kex and key names added, it’s definitely going to fail after negotiation, but I’ll be happy just knocking down failures as they come.

Thanks again! Pull request hopefully coming soon ;)

Harrycane on February 3, 2022

Hello,

I am facing the same problem as @mcronce and I stumbled upon this thread. Now I’m wondering if you had any success in implementing diffie-hellman-group14-sha1 or if there is any plan from @pmeunier to implement it?

Thanks!

pmeunier on February 3, 2022

No plan on my side at the moment, unfortunately. What do you want to do?

Harrycane on February 3, 2022

I am aiming to use thrussh to communicate with a device that sadly doesn’t implement curve25519-sha256@libssh.org. Before I try to undertake the task of implementing another kex, I wanted to see if anyone else have had any success with similar endeavors, or made any headway really. Also, if such an addition would be beneficial to the crate and potentially merged?

mcronce on February 3, 2022

Unfortunately, I did not have success. Time for that project became pretty limited, and the crypto stuff is a bit over my head, so I ended up with a solution (that I don’t love) where openssh deals with the network layer, spawns my process, and communicates with it over plain-text