SSH Encryption

From EIK wiki

Secure Shell (SSH) is a cryptographic network protocol meant to secure communications over an insecure connection between network devices. One of the ways SSH does this is by using a hybrid approach between asymmetric public/private key- and symmetric cryptography. [1]

SSH is most commonly used as a means for secure remote login and command execution, often in the context of a client-server interaction, but is also often used for authentication and in file transfers protocols (SFTP / SCP).

This article will discuss and explore, among other things, the possible ways of creating SSH-keys, the underlying methods of encryption, configuration and some general best practices concerning interactions with servers and ssh key management. It is therefore complementary to the article: "SSH for beginners."

Introduction

A cryptographic system like SSH is used when communications must be withheld from third parties (confidentiality), the identity of the other party needs to be verified (authenticity) and/or when you want to make sure that received messages have not been altered (integrity).[2] To understand how communications are encrypted in SSH we first need to understand some basic terms and concepts. The difference between asymmetric and symmetric cryptography is a good place to start.

Symmetric vs Asymmetric

Symmetric cryptography is something probably most people are and have been familiar with since their youth. An example: The alphabet has 26 characters and we assign each position a number (a='1', b='2' etc.), then we proceed to "shift" or "rotate" each character for n steps down this sequence. If we take n=1 for example, so that each letter gets "bumped up" one value and effectively taking the place of the character that was there before. This gives: z='1', a='2', b='3' etc). This algorithm is referred to as ROTn[3] (or Caesar Cipher[4]) where n would be the number of steps to rotate the characters. N would simultaneously be both the key to encrypt and to decrypt the message (hence the name 'symmetric'). An example message would be "Hello World", which we would encrypt with ROT13 to "Uryyb Jbeyq" and could decrypt with the same key back to "Hello World". Many people have experimented with this algorithm to encrypt messages during childhood and almost all people discover quite quickly how easy it is to break such encryption. Of course many more complicated versions exist [5] which are not as easily solved by hand but suffer the same underlying weaknesses as this simplified algorithm does and can get cracked quite easily with modern computing power using methods like frequency analysis.[6] The stress here is on keeping the key a secret, available only to the trusted parties and this is where the distinction with asymmetrical cryptography comes into play.

Asymmetric cryptography, using different keys to encrypt and decrypt, still works very similarly to what we have discussed before. There is an encryption algorithm available (previously the ROTn algorithm but in next parts we will discuss others like RSA and Ed25519) which "jumble" up the message depending on the specific key that is provided (this key will be known as the "public key" from now on) but where it differs is the decryption. Technically speaking the public key used to encrypt still contains all of the information needed to decrypt the message but this information is obfuscated by complexity and a modern computer's inability to retrieve this information in an acceptable amount of time. The other key in the pair (known as the "private key" from now on) is created alongside with the public key and allows for quick decryption of the message. This difference in decryption speed allows for safe sharing of public keys so that anyone wanting to send private data can encrypt it but only the holder of the private key can decrypt easily. The analogy that often comes up is that of the padlock and key: anyone who is provided a padlock (public key) can lock a message in a box, but only the person with the key (private key) is able to open the box and read the message.

Mathematical Concepts

To fully grasp the mathematical complexities of modern-day cryptographic systems one has to delve deep into number theory. This however, falls outside of the scope of this article and we will therefore only superficially touch on these subjects. Two concepts needed to start understanding these are modulo and primes.

When two integers are divided we obtain a quotient (e.g. how often the integer fits in the other) and a remainder. For example 19/5 = 3 with remainder 4, the remainder is referred to as the modulo. In different notation this becomes: 19mod5 = 4.

Prime numbers are positive integers which are only divisible by 1 and themselves (leaving 0 as remainder). The unique-prime-factorization theorem states that any positive integer greater than 1 can be written as a unique product of prime numbers. [7] These are important ideas to keep in mind when moving on to the next part where we will discuss the inner workings of the RSA-algorithm.

RSA vs Elliptic Curve

   !Warning! It is highly advised to trust standardized implementations of the following methods and not write your own. 

RSA

A message can be encrypted into a cipher text (C) if we first represent it as a number (M) according to a character encoding standard like ASCII. Here each character is represented using 7 bits for a total of 128 unique characters, although other encoding standards are available (UTF-8 / -16, extended ASCII etc.) which use more bits per character and thus support a greater variety of characters.[8] "Hello World" would turn into the following sequence of numbers: "072 101 108 108 111 032 087 111 114 108 100". The RSA algorithm proceeds as follows:[9]

   1) Create a numerical representation of original message (similar to our "Hello World"-example)
   2) Choose two (very large "random") primes p and q, which result into: n = p * q
   3) Choose a number d which is a relative prime of: (p-1) * (q-1).
      By relative prime is meant that the greatest divisor of d and (p-1) * (q-1) must equal '1'. [10]
      d can be chosen relatively easily by picking a prime number larger than either p or q
   4) Compute a number e using numbers d / p / q and Euclid's Algorithm.[11] e and d are so-called multiplicative inverses.
Fig.1 RSA encryption / decryption

e and n are provided as the public key and are meant to encrypt. d and n are kept as the private key and are meant for decryption. The two formulas presented are used to gain the cipher text from a desired message (encryption) or the message from the received cipher text (decryption). A method to gain the value of M^e / M^d is given by the original authors of the RSA-algorithm by "exponentiation by repeated squaring and multiplication". They refer to volume 2 of Donald Knuth's algorithm bible "The Art of Programming"[12] for more efficient approaches. For an introduction some good materials are also available through the Khan Academy: "Modular Exponentiation".

Example

   1) We have a message "Hello World" which we will translate into numerical values.
      
   2) We choose a prime p = 5  and a prime q = 11. The product of these two result in n = p * q = 5 * 11 = 55.
   3) t = (p-1) * (q-1) = 4 * 10 = 40. This gives us some options to choose a value d, in this case we choose d = 23.

   At this moment we know almost every number needed for both encryption and decryption of our secret message. 
   Only e has still to be computed. This is done using Euclid's Extended Greatest Common Divisor-algorithm.
   e's relation to d is described as such: e * d mod n = 1.

   Figure 3 displays the example worked out, producing the value of e = 7. 
   The following video describes the algorithm in a practical way: "RSA Walkthrough"
   The only difference is in choosing e in the beginning and deducing the value of d, but the method stays the same.

   Now that we have our desired values we can start encrypting our message.
   The first character of our message = 'H'. This is the 8th letter in the alphabet so let's say 'H' = 8.
   To get the cipher text value we have to raise the numerical value of each character to 7 and get the modulo of 55.

   The numerical values of our message are originally (without space character): "08 05 12 12 15 23 15 18 12 04"
   Encryption: 8^7 mod 55 = 2. And when we continue we get the full new message: "02 25 23 23 05 12 05 17 23 49"
   Decryption takes the inverse, raising to the power d: 2^23 mod 55 = 8. Thereby retrieving our original data.
Fig.2 Certificate signed with 2048-bit RSA

Unfortunately RSA on itself is deterministic and therefore clearly unsafe to use as such. Our example uses small numbers, so obfuscation is introduced by choosing the values of p, q, e / d high enough but related problems would remain. To resolve this, one has to add padding to the encryption to ensure a random-factor in the ciphered message. This ensures that the code could only be broken by an attacker if either n is factored or d is obtained from e.[13]

An additional problem with RSA is that it is very slow compared to symmetric encryption algorithms. It is often used as a way to exchange / create a shared symmetric key to bypass the inherent key-exchange problem symmetric-key based encryption systems have instead of encrypting each piece of information fully with RSA. These created keys are therefore used for authentication while the symmetric keys are used for the actual encryption of the connection and the client-server traffic to ensure confidentiality.[14]

Many more possible problems can arise when using RSA but current implementations are considered very robust. The largest factored RSA-number known stems from 2010 and was 768-bit long.[15] It is estimated that the first 1024-bit keys could be deciphered already and therefore a minimal key length 2048-bits is recommended but higher might be preferable. Certificates are signed with 2048-bit keys as you can see in figure 2.

Additional information on recommended random number generators / hashing functions are described in "PKCS #1; version 2.2". Interested readers might start looking into schemes like OAEP[16] and NP problems[17].

Fig.3 Euclid's Algorithm

Elliptic Curve

Fig.4 Elliptic curves following y^2 = x^3 + ax + b. Values 'a' and 'b' are defined.

The level of security gained by using an implementation of RSA hinges on the factorization problem of very large numbers, elliptic curve cryptography achieves this security through the "Elliptic Curve Discrete Logarithm"-problem. To illustrate we can consider an elliptic curve of the form: y^3 = x^2 + ax +b. Figure 4 shows an elliptic curve with a range of values for 'a' and 'b' on this curve. Notice the curve where the values a = 0 and b = 0. It produces a "knot" or rather a "singular point" which disqualifies these values for a and b to be considered. Figure 5 starts illustrating how we can obtain public-private key sets by choosing two points on any given curve (A, B), drawing a line between them, determining the intersection with the original curve (C) and mirroring this point on the x-axis, producing the final point (C'). Similarly we can "add" point A and B (both have the same coordinates), take the angle of that point on the curve and produce a third point C which, again-mirrored in the x-axis, produces C'. We can rewrite this as a scalar multiplication: C = 2A. This procedure is seen in Figure 6. The "Elliptic Curve Discrete Logarithm"-problem basically states that scalar multiplication on an elliptic curve is a "one-way-function"[18] by way that if points A and C' are known, it is very hard to determine what the factor (in this case 2) between them is. With hard we again refer to computational time complexity. These examples work with a set of real numbers while in practice this is done with a set of integers.[19]

Diffie Hellman

It is good to note that both algorithms discussed are used for authentication in the ssh process to make sure that both parties can verify who the other is. Upon initial contact the two parties however will first go through a key exchange process to determine a mode of encryption to ensure that all further contact is done in secrecy (confidentiality). This process is called the Diffie-Hellman exchange and is currently done by default with ECDH (Elliptic Curve Diffie-Hellman) in OpenSSH (Although other key exchange protocols are supported) [20]. One more note before moving on: it is important to keep in mind that the public-private keys in Diffie-Hellman and for authentication are not the same.

During the actual process the following domain parameters are public to all (including possible attackers):

 -> The curve itself including the finite field (set of elements described as the modulus of some prime number)
    and values for 'a' and 'b'.
 -> A generator point G (in figure 6 this was point A).
 -> The size of the list of points this base point creates by scalar multiplication (also known as the order).
 -> Co-factor which is the number of elements on the curve divided by the order (Optimally approaches 1).

When two people (Bob and Alice) want to communicate securely (so that Eve can intercept traffic but not decipher) the following procedure will happen:

 -> Bob will choose a number beta (his private key) which is an integer between 1 and the order-1.
 -> Bob will calculate BETA (earlier point C'), which is a point on the curve. 
    Using the same logic as our earlier example: G * beta = BETA.
 -> Alice will do both these steps for alpha and ALPHA.
 -> Both exchange the calculated coordinates ALPHA and BETA. 
 -> Eve can still hear all of this; she however doesn't know how many "steps" away from the 
    generator point ALPHA and BETA are.
 -> Bob will now multiply the received ALPHA times his secretly chosen number beta 
    and Alice will do the same.
 -> This produces the same new point GAMMA on the curve which only they know, bypassing 
    Eve and leaving her to crack the code.
Fig.5 Geometric addition of two points on an elliptic curve: y^2 = x^3 - 4x + 1. A+B=C'

This process not only ensures that any single session is authenticated and secure, but since it initiates this process during each session it also makes sure that if a session-key is broken (by stealing the private key of the session) only that session is compromised but not any others. This is also why one doesn't use the authentication keys to encrypt the session since all sessions would share the same weakness: confidentiality of the private key. [21] Since encrypting each message with this established key is a costly operation, a shared symmetric-key algorithm is negotiated with an accompanying secret key to actually encrypt the rest of the session. To see the list of allowed ciphers in order of preference see: man sshd_config.[22]

A great step-by-step video on this process can be found here: "Elliptic Curve Diffie Hellman". This video also goes through some example calculations on how to create cyclic groups, e.g. the points on our chosen curve. In real life these curve parameters are much bigger and often pre-calculated so as to make implementation easier to use since calculating and then verifying the strength of the curve is a task too heavy for most systems. A good article running through some sample maths hosted on a blog which provides great context: "Elliptic Curves".

Fig.6 Geometric addition of two points on an elliptic curve: y^2 = x^3 - 12x. A=B -> A+B=2A=C'

Reflection and Conclusion

We have talked so far as to how ssh-keys are created and a little on where they are used, but it is good to describe and repeat how they are used. Let's say we want to connect to a server and we have created our key-pair, how do we authenticate or know for sure that we are talking to the actual server and not a "man-in-the-middle"? How do we ensure integrity and confidentiality in our communications? And which algorithm is safer?

When you create your key-pair you are presented with a Random-art and hashed version of your public key, similarly you will be presented with a hashed version of a server's public key upon initial contact (Old versions use MD5 - later ones default to SHA-256). These hashed versions represent human-readable "non-reproducible" formats of these keys so that one can compare them easily with a publicly published version of that key. Hashes of the server keys can be hosted on a web-server so that anyone who wants to connect to that machine will be able to gain the key information from two separate places and determine that they are one and the same. There is an additional point of authentication that happens upon connection to a server. It presents the client with a message encrypted with its private-key which can be deciphered using the public key that gets presented in parallel. By comparing the hashes of the public key we know it belongs to our specific server while using the public-key to decipher the message verifies that the server is in possession of the accompanying private-key. This all reduces risk, but unfortunately still presumes that you trust the site or source of the published public-key of the server (HTTP vs HTTPS comes into play here) and while you could ask system administrators if no published keys exist, it comes down to your personal judgement whether to trust that source or not. After the known_hosts and authorized_keys files have been checked for the presented keys, the Diffie-Hellman procedure will commence to further encrypt the ssh session and ensure confidentiality.

Data integrity is ensured by a "hash-and-encrypt" method. Each message sent will be run through a hashing algorithm and subsequently encrypted using the party's private key. The receiving party is in possession of the public key and thus able to decipher the hash, run the message through the hashing algorithm and check if the two correspond with each other. This not only ensures data integrity but ensures authenticity of the message. This is called the HMAC (Hash-based message authentication code). The MAC is calculated from the symmetrical shared secret, the packet sequence number of the message, and the actual message content. The hash algorithm is similarly to the session-cipher negotiated right after the Diffie-Hellman key-exchange.[23]

The safety of the algorithms described falls outside of the scope of this article but a few important findings are worth noting. First considering the Diffie-Hellman exchange. Traditional DH uses the same type of process as described but using a RSA-like prime-number based approach. Since computation time can be long for that process it was considered safe to pre-compute certain values as long as bit-values were high enough. It turns out that a very significant portion of the internet was using the same pre-calculated values with 512 and 1024-bit numbers, leaving all systems that did compromised. This vulnerability is known as Logjam[24] and was estimated to break 2/3's of VPN's and 1/4 of all SSH servers globally after breaking just one prime. Recommendations included switching to 2048-bit DH or to ECDH by upgrading to the latest version of OpenSSH.[25]

Elliptic curve is currently considered preferable over RSA but does have some general side notes. As mentioned before, implementations use predefined curves and generator points which raises concerns over possibly introduced backdoors.[26] This has happened at least once before in an elliptic curve based random number generator.[27] The "safe-curves" project has been established to ensure access to curves which have been developed in a publicly verifiable way so as to minimize the chance of an introduced backdoor.[28] Future introduction of quantum computers might make RSA more preferable than elliptic curves due to Schor's algorithm.[29]

For more on SSH keys, including possible risks one can visit: "Secure Shell Home".

Configuration, Commands and Considerations

SSH-key Audits and Verification

We can obtain the public keys provided by a server without connecting to it by using the following command. There are usually more than one provided to retain compatibility. (Enos server provides 3: ECDSA / Ed25519 / RSA)

 $ ssh-keyscan <ip><url>

The hash for these can be obtained using the following commands. Only providing the -l -f switches will provide the default hash depending on the OpenSSH version used, but can be modified with the -E switch.

 $ ssh-keygen -l -f <file with server's public-key>
 $ ssh-keygen -l -f <file with server's public-key> -E md5

These commands can be helpful in determining the authenticity of servers. Of course these commands can also be used in case a service is performing a SSH Key Audit and you need to find out the hash of your own public key.

Key Strength

OpenSSH allows for two types of elliptic curve public-private key configurations: ECDSA and Ed25519. The former comes in three key-length sizes (256 / 384 or 521 bits) and attempting configuration with altering sizes will fail, while the latter has a fixed-length of 256-bits and depends further on implementation.[30] Of the two Ed25519 is recommended to be used and has been available for use since OpenSSH version 6.5[31] while ECDSA has been around since OpenSSH 5.7.[32] Since the ssh-keygen command still defaults to RSA, one has to indicate specific configuration through the -t switch.

 $ ssh-keygen -t ecdsa -b {256|384|521} 
 $ ssh-keygen -t ed25519

Although a direct comparison is hard to make between the strength of elliptic curves vs. rsa based encryption, safety recommendations of several governmental and independent agencies identify a ~250 bit elliptic curve and a ~3000 bit rsa, factoring modulus key to be of equal strength.[33]

Private Key Safety

If implemented well, SSH-keys allow for safe, trusted communications between clients and hosts. This is however fully dependent on the safety and secrecy of the private key, a few things can be done to reduce ease of access to the keys by unauthorized persons.

Ed25519 keys use a new OpenSSH format to save private keys upon generation which provides additional resistance to brute-force password cracking.

 When storing passwords you want to use an algorithm that is computationally intensive. 
 Legitimate users will only need to compute it once (for example, taking the user’s password, 
 running it through the KDF, then comparing it to the stored value), while attackers will need 
 to do it billions of times. Ideal password storage KDFs will be demanding on both computational 
 and memory resources.[34]

RSA and other key-generation algorithms default to the old format but this is configurable with the -o switch. The ssh-keygen command can then be combined with the -a switch which defines the amount of KDF (key derivation function) rounds used. A higher number of these rounds results in slower passphrase verification. This is possible with any SSH2 protocol key but is not supported by OpenSSH before version 6.5.[35]

 $ ssh-keygen -o -a <# of KDF rounds>  (Defaults into RSA-based key-pair)

You can update your old generated keys to the new format as such:[36]

 ssh-keygen -o -p -f id_ecdsa -a 1000
 Enter old passphrase:
 Key has comment 'id_ecdsa'
 Enter new passphrase (empty for no passphrase):
 Enter same passphrase again:
 [wait 30 seconds]
 Your identification has been saved with the new passphrase.

Of course one needs to also properly configure the permissions of any relevant files and directories like the ~/.ssh/authorized_keys file and the ~/.ssh/ directory to keep them owned by the user and non-world writable.

SSH Hardening

Once proper SSH-key authentication has been set-up on a server, one can disable password login for root or just for all users. This increases security since a password is not only more susceptible to be broken through brute-force attacks it is also sniffable.[37] Other (more frowned upon) techniques include changing the default ssh port 22 and/or setting up scripts (fail2ban) that atempt to detect brute force attacks and block attackers with additional firewall rules.[38][39]

 $ sudo nano /etc/ssh/sshd_config

In the configuration of the ssh daemon find the lines "PermitRootLogin" and "PasswordAuthentication" and modify it so that users can only connect with their SSH-key.[40]

 PermitRootLogin without-password

or:

 PasswordAuthentication no

And restart the service.

 $ sudo service ssh restart
 $ sudo service sshd restart

This all means we can only access our host through the use of SSH-keys and (if a passphrase has been set. See: SSH for beginners) we need to access our private keyfile every time we do so. Entering the passphrase is a risky transaction and annoying on top of that. A SSH-Agent is a program that runs in the background, keeps private keys in memory and issues signing operations to any programs that need access to them. The SSH process gets locked out from access to your keyfile and instead gets handled by the ssh-agent process. You can add keys to it by entering:

 $ ssh-add <path to keyfile>

And list all added keys (in fingerprint format) by issuing:

 $ ssh-add -l

The ssh-add command has a few other useful switches one can use like the -x to lock the agent with a password, -X to unlock it and -t to set a maximum lifetime of a key in the agent (measured in seconds by default. Alternative with same effect: ssh-agent -t). Something that one can consider using is Keychain which is a front-end to ssh-agent and ssh-add. Some resources on that topic: Official Project Page / ArchLinux Keychain Subsection / Basic usage

One wants to probably only allow known users to connect to your server through SSH. One can add users to the AllowUsers section in the sshd_config file to regulate who gets access. When users are deleted, their credentials will remain in this file though so the AllowGroups option provides for us. We can create a ssh-user group to which we can add members which will loose access after deletion. Go to the /etc/ssh/sshd_config file and add:[41]

 AllowGroups ssh-user

Another safety feature would be to set idleness timeout intervals (in this case the user gets "kicked-out" after 3minutes):[42]

 ClientAliveInterval 300
 ClientAliveCountMax 0

Some features of OpenSSH are undocumented and rarely used. One feature with a known vulnerability is UseRoaming and could be turned off in the same config file:

 Host *
  UseRoaming no

Two Factor Authentication

In addition we could require any incoming ssh-connections to complete a two-factor authentication process. Implementations commonly use "something you know" (password), "something you have" (physical device) and/or "something you are" (fingerprint).[43] There are multiple 2FA systems available for Linux so let's first explore the popular open-source package google-authenticator.[44] It uses a PAM module, which is a framework for system-wide user authentication[45][46], is available for many distributions / phone operating systems and has been tried and tested now for a number of years. It uses a time-based algorithm, plus a secret key generated upon initial set-up to generate a unique code for each login. To install on Debian-based system:

 $ sudo apt-get install libpam-google-authenticator

Users also need to set-up the Google Authenticator App[47] and create a secret key when they are logged-in on the server. This is done through the following steps:[48]

$ google-authenticator
  Do you want authentication tokens to be time-based (y/n) y
  <Here you will see generated QR code>
  Your new secret key is: ZVZG5UZU4D7MY4DH
  Your verification code is 269371
  Your emergency scratch codes are:
    70058954
    97277505
    99684896
    56514332
    82717798
  
  Do you want me to update your "/home/username/.google_authenticator" file (y/n) y
  
  Do you want to disallow multiple uses of the same authentication
  token? This restricts you to one login about every 30s, but it increases
  your chances to notice or even prevent man-in-the-middle attacks (y/n) y
  
  By default, tokens are good for 30 seconds and in order to compensate for
  possible time-skew between the client and the server, we allow an extra
  token before and after the current time. If you experience problems with poor
  time synchronization, you can increase the window from its default
  size of 1:30min to about 4min. Do you want to do so (y/n) n
  
  If the computer that you are logging into is not hardened against brute-force
  login attempts, you can enable rate-limiting for the authentication module.
  By default, this limits attackers to no more than 3 login attempts every 30s.
  Do you want to enable rate-limiting (y/n) y

As you can see one can increase the time any token is valid from 30 seconds to 4 minutes, this might be necessary if delays between client and server are expected. One can also set rate-limiting and allow/disallow the same code to be reused. Obviously these settings as presented would prove most secure. You will now see a series of codes, the first one of which is the secret key one can enter into the app. You can also install libqrencode and it will then display a scannable QR-code.

 $ sudo apt-get install libqrencode-dev

The emergency scratch codes are important to note down and keep safe. These will allow you to get back into the system if you were to lose your phone which allows you to run the same $ google-authenticator command again and generate a new secret key. They are stored in the ~/.google_authenticator file for later reference when you are logged in.

This still leaves us with configuring the PAM configuration file on the server. Depending on how you want to use the two-factor authentication one has to either configure the /etc/pam.d/sshd or the /etc/pam.d/system-auth configuration file. We are talking about remote login so the /etc/pam.d/sshd file applies to us, but can be configured globally in the other. Add the following line to the top of that file:

 auth required pam_google_authenticator.so

It is important to do so since order matters in this file. Only users who have generated a secret key file will be allowed to log in using ssh. Keep this in mind before implementing the system and inadvertently locking people out. Configuring SSH is also necessary. Go to your /etc/ssh/sshd_config file and add the following:

 ChallengeResponseAuthentication yes

If you disabled password-based authentication and only allow for key-based authentication one has to also add the following:

 AuthenticationMethods publickey,keyboard-interactive

Restart the service and you should be ready to go.[49][50]

Fig.7 Yubikeys

Another way to add a physical layer to the 2FA-process is Yubikey. It is a physical device that plugs into your pc or laptop and will either pretend to be a keyboard and types an OTP (one-time-password) or submit a stored ssh-key when you touch it. The password could then be validated by a third party service. This way even if your private key lands into the hands of another person, they would still need access to this physical part of the authentication process. Similarly if one were to use the ssh-keys on the device itself, the keys would be protected from any ransom- or crypto-ware. To install add the PPA and install the necessary package. These following steps are for authentication using the OTP.

 $ sudo add-apt-repository ppa:yubico/stable
 $ sudo apt-get update
 $ sudo apt-get install libpam-yubico 

Then create an API-key and proceed to the /etc/pam.d/sshd folder to allow for yubikey authentication by putting the following on the top of the file:

 auth sufficient pam_yubico.so id=[Your API Client ID] key=[Your API Client Key] debug 
 authfile=/etc/yubikey_mappings mode=client

You need to create a relationship between keys and users on your system. You can create such a "mapping file" either in the user's home directory or one mapping with all keys. For more details see: Section Authorization Mapping Files. Depending which one you opt for, you either need to configure PAM or create an "authorized-keys" like file. The remnant steps are similar to the google-authenticator configurations in the /etc/ssh/sshd_config file.

 ChallengeResponseAuthentication yes
 AuthenticationMethods publickey,keyboard-interactive:pam

Before restarting your SSH Daemon it is wise to test any new configurations using the -t (Test mode) and -T (Extended test mode) switches. These commands should not return any errors or text.[51]

 $ sshd [-t] [-T]
 $ service sshd restart

To use the yubikey in combination with ssh see the following tutorials / walkthroughs and reference materials: Yubikey-Guide / GPG in smart-cards / Ubuntu Forum - Yubikey Neo for login / Yubikey for SSH / HTTPS Athentication tokens / Yubikey as hardware token for GPG

Wrap Up

Some additional keywords, considerations and other materials that were either beyond the scope of this article or were beyond the author's schedule but bear mentioning anyways. Firewalling of SSH ports / Lock users to their respective home directories / Rate limiting / Disallow Port Forwarding Proper agent forwarding / Avoid SSH cross-server No Empty Passwords / Disable rhosts / MaxAuthTries / Ciphers and Algorithm Choices / How to harden TLS and SSH / SSH CA for host-client validation

See Also

Other

 Author:  Frank Korving
 Group:   CSE-11

References

  1. [1]"RFC4251". Retrieved 04.04.2017
  2. [2]"Kleptography, cryptography with backdoors." Retrieved 04.04.2017
  3. [3] "It's important to keep this document secret, so we encrypted it with ROT13, and, for extra security, we applied it twice!" Retrieved 22.02.2017
  4. [4]"Mod26". Retrieved 04.04.2017
  5. [5] Polyalphabetic Ciphers and how to crack them. Retrieved 22.02.2017
  6. [6] Famous cracking of the Nazi Enigma Code using repeated stereotypical messages. Retrieved 22.02.2017
  7. [7]Basic proof of prime factorization. Retrieved 06.04.2017
  8. [8]ASCII. Retrieved 06.04.2017
  9. [9]Original paper describing RSA-algorithm. Retrieved 06.04.2017
  10. [10]Euler's Totient. Retrieved 06.04.2017
  11. [11]Euclid's Algorithm. Retrieved 06.04.2017
  12. [12]The Art of Programming, vol.2 - Knuth. Retrieved 06.04.2017
  13. [13]The RSA-problem. Retrieved 07.04.2017
  14. [14] Understanding SSH encryption and connection. Retrieved 30.04.2017
  15. [15]768-bit RSA-key cracked. Retrieved 30.04.2017
  16. [16]OAEP. Retrieved 07.04.2017
  17. [17]P vs NP Time Problems by Computerphile. Retrieved 07.04.2017
  18. [18]One way functions and the discrete logarithm problem. Retrieved 30.04.2017
  19. [19]Introduction of Elliptic Curve Cryptography. Retrieved 30.04.2017
  20. [20]Diffie-Hellman. Retrieved 04.05.2017
  21. [21]SSH & DH. Retrieved 04.05.2017
  22. [22]sshd_config. Retrieved 05.05.2017
  23. [23]Hashing in SSH sessions. Retrieved 05.05.2017
  24. [24]Logjam. Retrieved 04.05.2017
  25. [25]Weak Diffie-Hellman. Retrieved 04.05.2017
  26. [26]Critique on Elliptic Curves. Retrieved 08.05.2017
  27. [27]Dual_EC_DRBG. Retrieved 04.05.2017
  28. [28]Safe Curve Project. Retrieved 04.05.2017
  29. [29]Schor's Algorithm. Retrieved 04.05.2017
  30. [30]Man-page of ssh-keygen command. Retrieved 30.04.2017
  31. [31]OpenSSH 6.5. Retrieved 08.05.2017
  32. [32]OpenSSH 5.7. Retrieved 08.05.2017
  33. [33]Keylength recommendations. Retrieved 08.05.2017
  34. [34]KDF. Retrieved 08.05.2017
  35. [35]Arch Linux - SSH Keys. Retrieved 08.05.2017
  36. [36]bcrypt pbkdf. retrieved 08.05.2017
  37. [37]SSH Best Practices. Retrieved 08.05.2017
  38. [38]Two factors better than one. Retrieved 05.05.2017
  39. [39]Hardening SSH. Retrieved 05.05.0217
  40. [40]Disable password server-side. Retrieved 05.05.2017
  41. [41]Secure Secure Shell. Retrieved 08.05.2017
  42. [42]OpenSSH Server Best Practices. Retrieved 08.05.2017
  43. [43]YubiKey 2FA on Ubuntu SSH. Retrieved 08.05.2017
  44. [44]Google Authenticator - Github. Retrieved 05.05.2017
  45. [45]PAM - Pluggable Authentication Modules. Retrieved 05.05.2017
  46. [46]PAM - Distribution site. Retrieved 05.05.2017
  47. [47]Set-up 2FA through Google authenticator using App. Retrieved 05.05.2017
  48. [48]Google Authenticator - ArchLinux Walkthrough. Retrieved 05.05.2017
  49. [49]Digital Ocean - 2FA. Retrieved 05.05.2017
  50. [50]Multi-Factor Authentication, Digital Ocean. Retrieved 05.05.2017
  51. Audit and harden your SSH configuration. Retrieved 08.05.2017