SSH commands - the Secure SHell commands

mail

ssh-add

Usage

add / list / remove private keys to/from the OpenSSH authentication agent :
mail

ssh-keyscan

Usage

Flags

Flag Usage
-H Hash all hostnames and addresses in the output so that hashed names may be used normally by ssh and sshd, but reveal no identifying information should the file's contents be disclosed
mail

scp

Usage

Copy files between hosts on a network using the SFTP protocol over a SSH connection.

Flags

Flag Usage
-p preserve file permissions + timestamps

Example

Copy files :

  • in "push" mode :
    scp path/to/localFile sshServer:/remote/destination/directory
  • in "pull" mode :
    scp sshServer:/path/to/remoteFile local/destination/directory
  • as a specific user on the remote system :
    scp /path/to/localFile bob@sshServer:/remote/destination/directory
mail

ssh-keygen

Usage

Generate / manage / convert / SSH keys

Flags

Flag Usage
-a numberRounds When saving a private key, this option specifies the number of KDF rounds used.
Higher numbers result in slower passphrase verification and increased resistance to brute-force password cracking (should the keys be stolen).
-b numberBitsKey Specifies the number of bits in the key to create, which depends on the key type.
-C comment Will append comment at the end of the public key (myKey.pub) :
ssh-rsa AAAAB3NzaCDvrOAYDtfSbKsIzDt4fOKQ1yc2EAUadaPsKA2ofpo95n/Altv9t4mu1Ob/YHaZcdX0aCzS7WVQ== comment
ssh-ed25519 AAAACxOtLlwWTzud97ZBIpcQ3NzaC1lZDI1NTE5IHyXmUPVMe+qyxB5II3CeXx9k comment
comment defaults to currentUserName@currentHostName
-f keyFile Specifies the filename of the key file.
-F host
-F [host]:port
Search host in the specified key file
If ~/.ssh/known_hosts has an entry such as :
[12.34.56.78]:443 keyType base64PublicHostKey
the syntax that may return it is :
ssh-keygen -F '[12.34.56.78]:443' -f ~/.ssh/known_hosts
-N newPassphrase Specifies the new passphrase
-o save private keys using the new OpenSSH format rather than the more compatible PEM format. The new format has increased resistance to brute-force password cracking but is not supported by versions of OpenSSH prior to 6.5 (check it : dpkg -l | grep openssh).
ed25519 keys always use the new private key format.
-p Requests changing the passphrase of a private key file instead of creating a new private key. The program will prompt for the file containing the private key, for the old passphrase, and twice for the new passphrase.
-R host Removes all keys belonging to host from a known_hosts file (example)
-t type Specifies the type of key to create :

Example

Create a ED25519 key :

The default OpenSSH key encryption is worse than plaintext :

Not sure how it could actually be "worse" than plaintext, but it sounds rather poor anyway (see gory technical details below). To workaround this :
  • replace old keys with keys using the new private key format :
    ssh-keygen -t ed25519
  • update private keys to the new storage format :
    1. privateKey=~/.ssh/id_rsa; oldPrivateKey="$privateKey.old"; cp "$privateKey" "$oldPrivateKey"; ssh-keygen -p -o -f "$privateKey"
    2. make sure the key pair still works (just in case...)
    3. rm -i "$oldPrivateKey"
  • This applies only to private keys having a passphrase. Commands will work on passwordless keys but are merely useless.
  • Compatibility with servers is not a concern, because the private key never leaves your machine.

Technical details :

Make a private key without passphrase (i.e. unencrypted private key, source) :
myKey='/run/shm/myKey'; ssh-keygen -N '' -f "$myKey"; head -5 "$myKey"; rm "$myKey"*
-----BEGIN RSA PRIVATE KEY-----
MIIEoAIBAAKCAQEA0Fcqiy4b2hoYLdy2jxgJ4n4Ek+S5rKCwfkbMTarq5WsSJ4Rf	MII... : the base64 DER clue that an RSA key follows
KBeDO5T1q8pjPefViRfJTuPIhWfdbivIkXIDdyGTOf+m6VufArnAW6kpj7cTWoeo
39L0qot4zV73LWv6aM/esLYqIuuY4bdZusEqEqdgMCB62uzo71CY3ti+F6o3VDUY
trMSFTQhyN/bqfhnrtBKpkmDnol4N6CThVpck1JFat0LDRu/hhtWdRlm2bmIgozv

The private key is an ASN.1 data structure, serialized to a byte string using DER, and then Base64-encoded.

View the ASN.1 structure (source):
myKey='/run/shm/myKey'; ssh-keygen -N '' -f "$myKey"; openssl asn1parse -in "$myKey"; rm "$myKey"*
Outputs the ASN.1 structure, made of 9 integers.
Make a private key with a passphrase (source) :
myKey='/run/shm/myKey'; ssh-keygen -N 'secret' -f "$myKey"; head -5 "$myKey"; rm "$myKey"*
----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: AES-128-CBC,D634E4857AF0E3B1EF0CA8518425C70E	"D634E4857AF0E3B1EF0CA8518425C70E" is the Initialization Vector (IV)

yJ66gBHIeKhDSBB0Bh6oJezrprNcv8BQ/QszaOD3Qgc5XaJW04yaVbX5btO2ucpD
Try to view its ASN.1 structure :
myKey='/run/shm/myKey'; ssh-keygen -N 'secret' -f "$myKey"; openssl asn1parse -in "$myKey"; rm "$myKey"*
fails because not in ASN.1 format anymore : it's encrypted
Generate an encrypted key, then decode it (source):
password='123456'; myKey='/run/shm/myKey'; ssh-keygen -N "$password" -f "$myKey"; openssl rsa -text -in "$myKey" -passin "pass:$password"; head -5 "$myKey"; rm "$myKey"*
==> displays the decoded key.
Trying to do it manually :

password='123456'; myKey='/run/shm/myKey'; ssh-keygen -N "$password" -f "$myKey"; head -5 "$myKey"
	-----BEGIN RSA PRIVATE KEY-----
	Proc-Type: 4,ENCRYPTED
	DEK-Info: AES-128-CBC,DD75D306F2CEADFCD9F5B0AA88E72368

	jVdXts1mwNg2ZLB0GhmODPB1YBfn3R5i9cUlsViE9hBCZMTfp0st5eyMTUy6Otlr

echo -n 123456DD75D306 | md5sum
	500d7daf9dac3883117c63b073996144

tail -n +5 "$myKey" | grep -v 'END ' | base64 -d | openssl aes-128-cbc -d -iv DD75D306F2CEADFCD9F5B0AA88E72368 -K 500d7daf9dac3883117c63b073996144 | openssl asn1parse -inform DER
	==> fails :-(((


openssl rsa -text -in "$myKey" -passin "pass:$password";
rm "$myKey"*
...
...
...

...doesn't work 

Long story short, the AES encryption key (used to encrypt the private key) is built with :

md5(passphrase + 8 first bytes of the IV)
  • MD5 is used in the process of encrypting the private key with the passphrase.
  • It is used only once
  • both AES and MD5 functions are cheap in terms of CPU and memory
this key is prone to brute-forcing, especially if the passphrase is short/poor quality

mail

ssh-copy-id

Usage

ssh-copy-id is a script used to copy your SSH public key to the specified host. If necessary, it can also create the remote :

Flags

Flag Usage
-i identityFile
  • use only the key corresponding to identityFile (i.e. do not try other existing keys)
  • .pub will be appended to identityFile if missing : identityFile is actually the public part of the key pair

Example

ssh-copy-id -i ~/.ssh/myProject/id_ed25519.pub mySshServer
/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/home/stuart/.ssh/myProject/id_ed25519.pub"
/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys

Password: t-o-t-a-l-e-m-e-n-t i-n-t-e-r-d-i-t

Number of key(s) added: 1

Now try logging into the machine, with:   "ssh 'mySshServer'"
and check to make sure that only the key(s) you wanted were added.
mail

ssh

Usage

There is a lot to say about SSH, since there are :

Flags

Flag Usage
-A Enable forwarding of the authentication agent connection (see ssh-agent, example)
You can enable this behavior in ~/.ssh/config with ForwardAgent yes.
-b bindAddress Use bindAddress on the local machine as the source address of the connection
-C Compress all data
This may be counterproductive on fast networks.
-e escapeCharacter Sets the escape character for sessions with a pty
  • default value : ~
  • none disables any escapes and makes the session fully transparent
-f Requests SSH to go to background just before command execution. Implies -n.
-F configFile Specifies an alternative per-user configuration file
to ignore your config file : -F /dev/null
-i privateKey identity file (aka private key)
defaults to ~/.ssh/id_rsa for RSA
-J jumpHost connect to targetHost via jumpHost :
ssh -J jumpHost targetHost
This is equivalent to using the ProxyJump client configuration directive.
-M Enable SSH Master mode allowing connection sharing (for details, see ControlMaster) (See -S)
-n Redirects stdin from /dev/null (actually, prevents reading from stdin).
-N Do Not execute a remote command, just forward ports (protocol v2 only).
-o option=value give options in the format used in the configuration file
-p port port number on which sshd will listen (default is 22).
-q quiet mode. Causes most warning and diagnostic messages to be suppressed (may be overzealous)
-S path/to/controlSocket
  • Specifies the path to the control socket for connection sharing —aka ControlPath
  • to be used with -M
-t Force pseudo-tty allocation (and fix the sudo: sorry, you must have a tty to run sudo error). This can be used to :
  • transmit signals between the SSH process and the remote one
  • allow sudo'ed commands to prompt for a password (example)
-T Disable pseudo-tty allocation. This proves useful only in scripts.
-v verbose mode. Repeat to increase verbosity : -vvv
-W host:port Requests that standard input and output on the client be forwarded to host on port over the secure channel. See ProxyCommand.
-X enable X11 forwarding
-Y enable trusted X11 forwarding. These are not subjected to the X11 SECURITY extension controls.

Example

Log on a remote host :

  • as a specific user :
    ssh bob@sshServer
  • + receive display of remote application :
    1. log in remote host :
      ssh -X stuart@sshServer
    2. start remote application
  • execute a remote application on its own (remote) display :
    1. log in remote host :
      ssh kevin@sshServer
    2. mangle its DISPLAY environment variable to use the local display :
      export DISPLAY=:0.0
    3. then start remote application

Send command to SSH host :

  • ssh kevin@sshServer 'command'
  • ssh -t haproxyServer 'sudo /usr/sbin/haproxy -c -V -f /etc/haproxy/conf.d/myConfig.cfg'
  • for server in server1 server2; do ssh "$server" 'df -h /home'; done

If the SSH session is interrupted (with CTRL-c or anything else) the remote process receives no signal and continues executing. To prevent this, you may allocate a pseudo-tty to SSH with -t. (source)