In this post, we’ll demonstrate how to setup automatic authentication to a Linux server using SSH and public key cryptography. Once properly configured, we’ll need only to provide the remote hostname to SSH to successfully authenticate.

SSH key pairs can be used to authenticate a client to a server. The client creates a key pair and then uploads the public key to a remote server it wishes to access. This is placed in a file called authorized_keys within the ~/.ssh directory in the user’s home directory on the remote host.

To follow along with this post, it is assumed that Cygwin is installed on a Windows client, and also that the user has access to a remote server accessible via Cygwin and SSH. For the code examples, commands entered and executed from the local Windows client are identified using the local> prompt, and remote> will be used to identify commands entered and executed from the remote server environment.

SSH Authentication

The SSH authentication process is as follows (see here for more information):

  • The client begins by sending an ID for the key pair it would like to authenticate with to the server.

  • The server check’s the authorized_keys file of the account that the client is attempting to log into for the key ID.

  • If a public key with matching ID is found in the file, the server generates a random number and uses the public key to encrypt the number.

  • The server sends the client this encrypted message.

  • If the client actually has the associated private key, it will be able to decrypt the message using that key, revealing the original number.

  • The client combines the decrypted number with the shared session key that is being used to encrypt the communication, and calculates the MD5 hash of this value.

  • The client then sends this MD5 hash back to the server as an answer to the encrypted number message.

  • The server uses the same shared session key and the original number that it sent to the client to calculate the MD5 value on its own. It compares its own calculation to the one that the client sent back. If these two values match, it proves that the client was in possession of the private key and the client is authenticated.

Setup

Open Cygwin, and navigate to the Cygwin /home/<username> directory (for this post, we’ll assume the username for the local and remote hosts is user1). The first step is to generate a key-pair:

local> cd /home/user1
local> ssh-keygen -t rsa

Accept the defaults for each option by pressing enter. After the first prompt, a .ssh directory will be created in the /home/user1 directory on the local client, and it will contain the generated public and private keys (check out this page for more information about the mathematics behind key generation). The public key will have the same name as the private key id_rsa, but with a .pub extension. You can display the contents of your generated public key cd’ing into your .ssh directory by passing id_rsa.pub to cat:

local> cd .ssh
local> cat id_rsa.pub

ssh-rsa 
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCyFOyCQ2VawpyLAcUx3sbcdAHc5TYlorJ/1AEXp9OQ462I
b7sQgAsPr3R/lBvBJ3rit6Nogbbl1Lm3c9Tl5JyOHRE88tp1uLpAfD3oEoGFgb5mSLz6yZ+6brPDS+PONiEi
MJtaZ3+zKTZkBfPomzEMUjhynS3aSn73mdChXPumSsbgod6Q4ZJVgPtCMKkD2vEdglTkC4qKXoyVYhvED31R
6qgW27tP+0bLGnyulK/PTtUQLCV+kQkB+FlZ54yQCumS2Os25WCXH5l7xGsIv1Lme3H+IezwUCuwHWsVsGqo
bnWY7hikTu8QJLhNqAzYhc3m3iklS2bh2sO8I5kBYWNZ user1@local

Next, open a new instance of Cygwin (this can be accomplished by pressing the Windows key + R, then entering mintty then Enter if Cygwin has been added to your PATH environmental variable). From the second terminal, we’re going to:

  • Login to the remote server via SSH
  • Create an .ssh folder in /home/user1 if it doesn’t already exist
  • Use the scp command to securely copy the public key (id_rsa.pub) from our local /home/user1/.ssh directory to our remote /home/user1/.ssh directory
  • Append the contents of id_rsa.pub to authorized_keys, a file that we’ll create on the remote host

We login to the remote server, then check whether or not the .ssh directory exists in /home/user1. In our case, it deosn’t, so we create it:

local> ssh -p 3333 user1@remote

# now on remote host:
remote> cd /home/user1
remote> ls -1a .ssh

# nothing returned, so we create it:
remote> mkdir .ssh

Notice in the first command, ssh was accompanied by -p 3333. This is an example of port forwarding, and is intended as an added security measure. If your server runs SSH on its standard port (22), you can omit this argument.

To find the port SSH is using on your remote server, you can run:

remote> echo ${SSH_CLIENT##* }
3333

Alternatively, if you can access to the /etc/ssh/sshd_config file, run:

remote> grep Port /etc/ssh/sshd_config
grep: /etc/ssh/sshd_config: Permission denied

But in this case, the user does not have access.

Back at the first terminal, we need to copy id_rsa.pub to the remote client via scp (‘secure copy’). Notice the port specification for scp is different that with SSH: -p specifies a port other than standard for SSH, whereas scp uses-P. We enter:

local> scp -P 3333 id_rsa.pub user1@remote:/home/user1/.ssh

We’re using scp via port 3333 to copy id_rsa.pub to /home/user1/.ssh on remote.

After pressing enter, , you’ll be prompted twice: The first time, press enter. The second time, enter your password. Upon doing so, you will receive a message indicating that the remote server has been added to the list of known hosts.

Back at the second terminal, ls –1 to verify that the public key was successfully copied over (Optionally, you can run cat id_rsa.pub to ensure that the key looks like it did when we first printed it to the terminal after it was created).

Next, we’re going to redirect the contents of id_rsa.pub into a file we’re going to call authorized_keys, then compare the two files to ensure their identical. If so, we can delete the remote copy of id_rsa.pub:

remote> cat id_rsa.pub > authorized_keys
remote> diff id_rsa.pub authorized_keys

# no difference; delete id_rsa.pub:
remote> rm -f id_rsa.pub

Finally, exit out of both terminals and open a new one. Login to the remote server as usual using SSH. The first login after setting up keys you may be prompted with a message requiring a yes/no response, but if the keys have been correctly configured, you should not be prompted for a password. If this is the case, congratulations! You’ve setup automatic authentication to your remote server!

SSH Configuration

It’s possible to create an SSH configuration file which allows you to bypass entering a port specification (‘-p 3333’) at each login. From the local client, in /home/user1/.ssh, create a file with notepad and name it config. Note that what Cygwin sees as /home/user1/.ssh, Windows sees as C:\cygwin64\home\user1.ssh, so when notepad prompts you to save the file, save it to C:\cygwin64\home\user1.ssh. In addition, make sure to save config without a file extension. When you go to save, in the ‘Save as type:’ dropdown, choose ‘All Files (*.*)’, and enter config without extension for the File name:. If you don’t do this, the file will be saved as config.txt, and will not be read by SSH at login.

In the config file, enter the options specific to your login details:

Host remote
    Hostname remote.com
    User user1
    Port 3333

Once saved, open Cygwin, and you will only need to enter the following to login to the remote server:

local> ssh remote
.
.
.
remote>

Troubleshooting

If after following the instructions you’re still required to authenticate with a password, it’s almost certainly a permission issue. You may need to change permissions for the following files and directories:

On local:
/home/user1/.ssh (700)
/home/user1/.ssh/id_rsa (600)

On remote:
/home/user1/.ssh (700)
/home/user1/.ssh/authorized_key (644)

(For more information about file permissions visit this page)

The required octal permissions to setup ssh authentication are listed after each file/directory above. These settings should be assigned by default, but in some instances may vary. To find octal file permissions for your files/directories, run the following:

$ stat --format %a <file_or_directory>

For example, if I wanted to check the directory permission of .ssh on my server, I’d run:

remote> stat –format %a /home/user1/.ssh
700

To change permissions, use the chmod command. For example, if my .ssh directory permission came back as 600, I could change it to 700 like so:

remote> stat --format %a /home/user1/.ssh
600
# change permission to 700:
remote> chmod 700 /home/user1/.ssh
remote> stat --format %a /home/user1/.ssh
700