[Crypto] SSH protocol dissected, part IV

Previous parts: 1, 2. 3. survey.

Picking algorithm

As you may see, SSH server and client usually offers a lot of different algorithms. Why not using a single one, just the best one? This is because shit happens. SHA1 was once broken ('SHAttered') and it can be expected that this can happen with any other algorithm. Even a renowned world-class expert like Ron Rivest ('R' in RSA) has produced an algorithm later broken: MD5. In such a case of emergency, sysadmins can just disable offending algorithm in SSH server config and switch to other.

So if a server has a list of algorithms to offer: A, B, C, D, and a client has its own list: D, B, X, Y, first common will be tacitly picked, but with priority left to client. In this case: D.

Pythonesque pseudocode:

for client_algo in client_supported_algorithms:
    for server_algo in server_supported_algorithms:
        if client_algo==server_algo:
	    return client_algo

# no common algorithm found.
# we can't go any further, report error and shutdown.

Other DH algorithms

In my previous parts, I started with diffie-hellman-group-exchange-sha256. Which was probably a bad idea. This method is slightly more complex than others -- a SSH server first negotiate about DH group (g/p). But SSH have other DH algorithms, with hardcoded g/p DH parameters, taken from RFC, such as: diffie-hellman-group14-sha1, diffie-hellman-group16-sha512, diffie-hellman-group1-sha1. Parameters are known to everyone, but this is OK.

Key extension

What if a DH algorithm produces only 160 bits (SHA1's digest), but encryption algorithm requires 512 bits (SHA-2-512)? And encryption algorithm requires 256 bits (AES-256)?

Naive solution is just to copy key several times so to fill inputs of SHA-2-512 and AES-256.

But the official SSH standard is more complex and considered more secure:

   If the key length needed is longer than the output of the HASH, the
   key is extended by computing HASH of the concatenation of K and H and
   the entire key so far, and appending the resulting bytes (as many as
   HASH generates) to the key.  This process is repeated until enough
   key material is available; the key is taken from the beginning of
   this value.  In other words:

      K1 = HASH(K || H || X || session_id)   (X is e.g., "A")
      K2 = HASH(K || H || K1)
      K3 = HASH(K || H || K1 || K2)
      ...
      key = K1 || K2 || K3 || ...

   This process will lose entropy if the amount of entropy in K is
   larger than the internal state size of HASH.

( RFC 4253 7.2 )

DSA and DSS

What is the difference? DSA is the algorithm and DSS is the NIST standard.

First, there was ElGamal in mid-1980s: 1, 2.

Then there was Claus P. Schnorr with his own scheme, that was kind of upgrade to ElGamal, and worked faster. But it was patented. Patent expired in 2008, and now it can be used even in Bitcoin. To circumvent this patent, NIST published modified scheme, named DSA. So Schnorr's scheme and DSA are very similar. For more information.

Also:

In 1991, NIST proposed the Digital Signature Algorithm (DSA) as an attempt to avoid
the patents on Schnorr signatures. For this reason, DSA is a weird variant of Schnorr
signatures, published without a proof of security (although no attacks have been
found so far). The algorithm was adopted by many but was quickly replaced with an
elliptic curve version called ECDSA (for Elliptic Curve Digital Signature Algorithm),
the same way Elliptic Curve Diffie-Hellman (ECDH) replaced Diffie-Hellman (DH),
thanks to its smaller keys (see chapter 5). ECDSA is the second signature algorithm I
will talk about in this section.

After the patents on Schnorr signatures expired in 2008, Daniel J. Bernstein, the
inventor of ChaCha20-Poly1305 (covered in chapter 4) and X25519 (covered in chap-
ter 5), introduced a new signature scheme called EdDSA (for Edwards-curve Digital
Signature Algorithm), based on Schnorr signatures. Since its invention, EdDSA has
quickly gained adoption and is nowadays considered state-of-the-art in terms of a digi-
tal signature for real-world applications. EdDSA is the third and last signature algo-
rithm I will talk about in this section.

( David Wong -- Real-World Cryptography )

DSA was used in OpenSSH till version 7.0 (not inclusive), then dropped. No one really knows why. DSA is still secure and can be used with keys larger than 1024 bits (but SSH used only keys with this length).

So far, we should know these facts about DSA:

DSS algorithms is defined in FIPS 186-3. DSA proof and more details are published in FIPS 186-1.

I implemented it with test vectors, as an exercise.

And then I implemented it in my toy SSH client. Works with clients which still support it. DSA key can still be generated by OpenSSH: ssh-keygen -t dsa. Resulting files: id_dsa, id_dsa.pub. As in case of RSA SSH keys, id_dsa.pub is also base64-encoded blob, containing p, q, g, y.


Download latest version: ~1600 SLOC.

UPD 20240529 13:34:05 EEST: Next part: SSH protocol dissected, part V: toy SSH client with ECC in ~2k SLOC of Python

(the post first published at 20221003.)


List of my other blog posts.

Subscribe to my news feed

Yes, I know about these lousy Disqus ads. Please use adblocker. I would consider to subscribe to 'pro' version of Disqus if the signal/noise ratio in comments would be good enough.