Blog‎ > ‎

Ussing Cygwin's ssh-agent in Windows

posted Sep 29, 2016, 6:45 AM by Juan Jose Garcia-Ripoll   [ updated Oct 9, 2016, 3:40 AM ]
When you want to log in to a Unix machine or some other kind of server, one of the favourite protocols is SSH. In public key authentication, you can generate a pair of keys, a private one called id_rsa and a public one id_rsa.pub These keys are usually stored in your HOME directory, with sufficient permissions so that no one can read the private key.

Unfortunately this may not always be the case. I have had machines that have been hacked, or I sometimes like to store my private-public key pairs in some backup device which may be in a not too secure location (for instance Dropbox). Under those circumstances it is useful to store the private key with a password, the so called "passphrase". Then, whenever you want to log-in to another machine using SSH you only have to type the passphrase.

ssh-agent is a program that stores your public and private keys in memories. Using it, you only have to introduce the passphrase once at the beginning of your session. It is convenient, it works under Linux but Windows does not have it built in.

Step 1: install ssh and ssh-agent

Your first stop for these programs in Windows will be cygwin. Get it from https://www.cygwin.com/ I use the 64-bit version, which works fine enough. After installation I recommend the following two changes:
  1. Edit the PATH environment variable to include the directory c:/cygwin64 or c:/cygwin depending on the version you chose.
  2. Create a HOME environment variable pointing to your favorite directory. I normally rely on the Windows one %HOMEDRIVE%%HOMEPATH%
Both changes together have the nice side effect that you can use SSH from anywhere, including Windows terminals.

Step 2: Create your public and private keys

Open a terminal and type
ssh-keygen -t rsa
and enter a long password as your passphrase. The longer the better. I usually rely on stupid sentences, like "the cow jumped over the 27th wall street", which have no meaning but have enough entropy and are easy to remember.

Step 3: Ensure ssh-agent is run when you log in

Press Windows key + R (both keys simultaneously) and enter shell:startup This will open a folder where you can create programs that run at boot time. Click with the right button and create a new "Text document". Enter the following text and save it with the name "run-ssh-agent.cmd" Note the different extension!
@echo off
rem Start ssh-agent in the background. It will not be closed
start /b ssh-agent > %HOME%\.ssh-agent-env
echo We need to ask you the password with which the SSH key is encoded
echo After that we will update the environment variable so that you
echo do not need to enter it again
pause
bash -c ". ~/.ssh-agent-env; setx SSH_AUTH_SOCK "$SSH_AUTH_SOCK"; setx SSH_AGENT_PID "$SSH_AGENT_PID"; ssh-add"

This step is quite critical because it is on charge of starting the agent that keeps the passwords in the background, decoding the SSH keys with the password you provide and notifying the whole of the system (via the environment variables SSH_AUTH_SOCK and SSH_AGENT_PID) that the SSH keys are available for use.

Step 4: Configure cygwin to use ssh-agent

Edit your profile file ~/.bash_profile and add the following lines at the end
SSHAGENT=/usr/bin/ssh-agent
SSHAGENTARGS="-s"
if [ -z "$SSH_AUTH_SOCK" -a -x "$SSHAGENT" ]; then
    if test -f ~/.ssh-agent-env; then
eval `cat ~/.ssh-agent-env`
    else
eval `$SSHAGENT $SSHAGENTARGS`
trap "kill $SSH_AGENT_PID" 0
    fi
fi

Step 5: Optional - Configure Emacs to use cygwin SSH

This is tricky. The problem is that Cygwin's SSH expect to be run from a Cygwin or MS-DOS terminal and does not like to run from within Emacs. There is a simple solution for this, which involves installing a package called fakecygpty from github (https://github.com/d5884/fakecygpty)

Step 6: Optional - Configure Emacs to use ssh-agent

I added the following function to my .emacs file (see here for configuration details) to read the location of ssh-agent and pass it to other functions, such as ssh or tramp.
(let ((filePath "~/.ssh-agent-env"))
  (with-temp-buffer
    (insert-file-contents filePath)
    (let (ssh-auth-sock ssh-agent-pid)
      (and (progn
    (goto-char (point-min))
    (re-search-forward "SSH_AUTH_SOCK=\\([^;]*\\)" nil t))
  (setq ssh-auth-sock (match-string 1))
  (progn
    (goto-char (point-min))
    (re-search-forward "SSH_AGENT_PID=\\([^;]*\\)" nil t))
  (setq ssh-agent-pid (match-string 1))
  (setenv "SSH_AUTH_SOCK" ssh-auth-sock)
  (setenv "SSH_AGENT_PID" ssh-agent-pid)))))