- File and Access Permissions
- Restricting Access to Resources With Pluggable Authentication Modules (PAM)
- Commands to Monitor System Users and Files
- Pretty Good Privacy (PGP)/GNU Privacy Guard (GPG)
- GNU Privacy Guard (GPG) Configuration
- Symmetric and Asymmetric Cryptography
- Encrypting Content
- Digitally Signing Content
- The Pretty Good Privacy (PGP) / GNU Privacy Guard (GPG) Process
- GNU Privacy Guard (GPG) Commands
- Documentation
- Checksums
- Secure Shell (SSH)
- OpenSSH
- System-Specific SSH Configuration
- User-Specific SSH Configuration
- Logging Into a Host
- The SSH Connection
- Verifying Remote Host Authenticity
- SSH Key Pairs
- Verifying Remote Server Authenticity
- Verifying Remote Client Authenticity
- Secure Copy (scp)
- Secure File Transfer Protocol (SFTP)
- SSH Port Forwarding (Tunneling)
- SSH Commands
- Documentation
GNU/Linux security is multi-faceted. Understanding, implementing, and interacting with the technologies that underlie GNU/Linux security will make you a better GNU/Linux user and administrator.
Note: If you are not familiar with the GNU/Linux command line interface, review the Conventions page before proceeding.
File and Access Permissions
A GNU/Linux file system can be described as follows:
- Everything is a file.
- There is a system of access permissions that is fairly simple, yet sufficient for most purposes.
Security consequences that follow from these points are as follows:
- Device files work anywhere in the file system, not just in
/dev/
. If an attacker manages to create a device file of the proper type (e.g.,/dev/sda
or/dev/kmem
), the system is compromised. The file does not even have to have the same name as the official device file, it just needs to have the correct type and major/minor device numbers. - Users can make any of their own files executable by setting their files'
x
bits. Usually, this is not a problem. Occasionally, problems are found in GNU/Linux that enable an unprivileged user to gain administrator privileges by executing a normal program, and that path is also available to programs that a user downloaded from the Internet. - The set-UID and set-GID mechanisms allow ordinary users to run programs with the permissions of other users (usually the root user). Set-UID and set-GID programs can also be located anywhere in the file system.
Minimizing Risk
You can attempt to minimize risk by restricting unusual file types to areas of the file system where such files are to be expected. However, you should also actively look out for possibly problematic files. Here are some recommendations.
Removable Media
Removable media are an obvious way to introduce unusual files to a system. This includes files of types that a user would not be allowed to create using their local account. For instance, an unprivileged user may not run a command like # mknod /home/amnesia/vacation.jpg c 1 2
, but if they manage to mount a USB stick that contains an ext4 file system with such a file, then they have succeeded.
GNU/Linux avoids this scenario by not letting ordinary users mount removable media at all. The only secure way to allow this is to add specific mount points to /etc/fstab
that contain the user
or users
mount
option.
Both of these options imply the nodev
option, which makes the system ignore device files on the mounted media (it also imples that SUID/SGID files on the associated media will not be functional). At this point, we could consider this issue resolved, but an /etc/fstab
entry like /dev/sda1 /media/usbstick auto noauto,user,dev 0 0
should not be created without considering its consequences.
Set-UID/Set-GID
Set-UID programs pose a similar problem. As ordinary users may not create device files, they many create set-UID files owned by root, and this is fine. However, just as a user might introduce a device file on a removable medium, they might introduce a small set-UID root program that will launch a shell.
Common shells like Bash are reluctant to let themselves be started as set-UID root processes. However, an attacker will likely not be stopped by this. They can also bring in their own shell that they compiled themselves with the set-UID detection code removed.
The way that GNU/Linux avoids this issue is essentially the same as the one that is used to handle device files. The user
and users
options to mount
also imply the nosuid
option, which prevents the execution of set-UID programs on the file system in question. To be precise, nosuid
does not prevent the programs from being executed, it just makes the system ignore the set-UID and set-GID bits.
The noexec
mount
option can prevent the execution of programs (including scripts) from the file system in question. This option is also implied by the user
and users
options. However, it does not present a big obstacle because a user can still copy the file to their home directory and execute it from there.
The nosuid
and nodev
options only protect against suspicious files on removable media (at first). They do not help against files created by clever attackers that exploit security holes in network services and create convenient backdoors, so that they can come back later. A set-UID shell with an innocuous name like .foo_bar_rc
would be sufficient.
There is nothing to keep you from enabling the nosuid
and nodev
options explicitly for all file systems where users can create files. Besides removable media, this mainly applies to the /home/
, /tmp/
, and /var/tmp/
directories.
You can scan your system for such files on a regular basis. The tool of choice for this task is the find command. To find all set-UID and set-GID files on your system, you can use find
's -perm
test.
The full command is:
# find '/' -perm /6000 -type f -ls
You should be aware of all of the set-UID and set-GID programs on your system. It is best to prepare a list that you manually check and later compare automatically (e.g., using a systemd timer or cron) to the list of actual set-UID and set-GID programs on the system.
Ensure that you are notified if a program on the list is missing from the system, or a program appears on the system that is not on the list. Some GNU/Linux distributions may do this by default.
Device files can be located in a similar way. Scan you system for files that are block or character devices:
# find '/' \( -type b -o -type c \) -ls
To run the command and skip the /dev/
directory, use the following form:
# find '/' -path '/dev' -prune -o \( -type b -o -type c \) -ls
The find
command can also be used to search for and remove rhosts
files from your home directory:
# find '/home' -iname .rhosts -exec rm -f '{}' \;
Having these files present can be a security risk, i.e., if you have a user that has a hostname in their .rhosts
file and that host also has the user's hostname in its /etc/hosts.equiv
file (this file contains a list of trusted hosts for a remote system, one per line), that user can log in without a password by using the rlogin
command.
Audit Automation
The auditing of your file system can be implemented more efficiently. Tools like Tripwire or AIDE are used to detect and report changes to important system files (both programs and configuration files). Typically, such modifications happen when rootkits are installed on a system.
Restricting Access to Resources With Pluggable Authentication Modules (PAM)
When multiple users share the same system, it is important that no single user is able to monopolize the system's resources to the detriment of other users. Even if you are the only user on a system, it may make sense to rein in single processes if they appear greedy.
To facilitate this, GNU/Linux offers a mechanism called resource limits. Resource limits let you specify upper bounds for various resources that users (or single processes belonging to them) may consume.
User access to GNU/Linux resources can be limited using a Pluggable Authentication Modules (PAM) module called pam_limits
. pam_limits
is configured using the /etc/security/limits.conf
file, which is used to apply ulimit
.
The /etc/security/limits.conf
file contains resource limits that you can configure using the following syntax:
ex_domain ex_type ex_item ex_value
ex_domain
- The entity to which the limit applies (e.g.,
user
,@group_name
,*
). ex_type
- Set soft or hard limit.
- Hard limits are set by the root user and enforced by the kernel. The user cannot raise their requirement of system resources above such a value.
- Soft limits are ones that a user can move up or down within the permitted range by any pre-existing hard limits. These values can be thought of as default values for normal system usage.
ex_item
- The resource being limited.
ex_value
- A value for the limit.
Resource limit items include:
core
- Restricts the size of core files (in KB).
cpu
- Restricts the CPU time of a single process (in minutes).
data
- Restricts the size of a program’s data area in RAM (in KB).
fsize
- Restricts the size of files created by the user (in KB).
locks
- Sets the maximum number of locked files.
maxlogins
- Sets the maximum number of simultaneous logins for users.
nice
- Sets the maximum nice priority a user is allowed to raise a process to.
nofile
- Restricts the number of data files a user may have concurrently open.
nproc
- Restricts the number of concurrent processes a user may run.
priority
- Sets the priority to run user processes with.
stack
- Restricts the stack size (in KB).
For example, the following line in /etc/security/limits.conf
sets a hard limit on the number of concurrent processes users in the guests
group can run to 10
:
@guests hard nproc 10
Documentation
For more information on on pam_limits
, run:
man 5 pam_limits
man 8 pam_limits
Run man 5 limits.conf
for more on the /etc/security/limits.conf
file.
ulimit
The ulimit
command sets or reports user process resource limits:
# ulimit ex_options ex_username
The ulimit -a
command is used to check the current user's ulimit settings:
$ ulimit -a
core file size (blocks, -c) 0
data seg size (kbytes, -d) unlimited
scheduling priority (-e) 0
file size (blocks, -f) unlimited
pending signals (-i) 15623
max locked memory (kbytes, -l) 65536
max memory size (kbytes, -m) unlimited
open files (-n) 1024
pipe size (512 bytes, -p) 8
POSIX message queues (bytes, -q) 819200
real-time priority (-r) 0
stack size (kbytes, -s) 8192
cpu time (seconds, -t) unlimited
max user processes (-u) 15623
virtual memory (kbytes, -v) unlimited
file locks (-x) unlimited
A specific username can be passed to ulimit -a
as an argument to view that user's ulimit settings.
For each of these resource limits, there is a soft limit and a hard limit. Administrator privileges are required to raise the hard limit. Regular users can lower a hard limit and set arbitrary soft limits, but only up to the current hard limit.
Hard limits and soft limits are modified using ulimit
's -H
and -S
options, respectively. When neither one or the other are specified, both the hard and soft limits are set to the same value. When no value is specified for a resource limit, its current value is displayed.
$ ulimit -n 512
$ ulimit -n
512
Above, ulimit
's -n
option specifies the limit on the number of file descriptors a process may have.
All resource limits can be interactively set using the ulimit
shell command. Then, they apply to the shell in which the command was entered, as well as to all processes that will be started by that shell (and their children).
In order to impose restrictive resource limits on users, you have to set them before the users gain system access.
Helpful ulimit
options include:
-c
- Limit the size of core files (i.e., crash dumps).
-d
- Limit the size of the user's process data.
-f
- Limit the maximum size of files created in the shell.
-H
- Set a hard resource limit.
-m
- Limit the maximum resident size (in KB) of a process in RAM.
-n
- Limit the number of open file descriptors or open files allowed.
-s
- Limit the maximum stack size (in KB).
-S
- Set a soft resource limit (e.g.,
# ulimit -S -u 50
). -t
- Limit the amount of CPU time allowed to the user (expressed in seconds).
-u
- Limit the number of processes that a given user can run.
-v
- Limit the maximum amount of virtual memory available to the shell.
Documentation
Run ulimit --help
for more information on ulimit
.
Commands to Monitor System Users and Files
There are several commands that can be used to gauge which users are on a system, what they are doing, and which processes are using which files.
whoami
The whoami
command prints the effective UID to the standard output.
$ whoami
amnesia
Essentially, the command is displaying the content of the LOGNAME
or USER
shell variables.
who
The who
command prints information about users that are logged on to the system to the standard output.
$ who
amnesia :0 2021-08-11 22:43 (:0)
The first column shows the username. The second column displays the terminal on which the user is logged in. :0
denotes the X11 server with that display name. Other names (e.g., pts/0
) refer to the device file below /dev/
. Terminal names of the form pts/
denote pseudo-terminals, typically terminal windows in a graphical environment or Secure Shell sessions.
The remainder of the line in the example above shows the date and time at which the session started. After that, the remote end of the session may be listed in parentheses. If you have several terminal windows or one terminal window with several tabs, it is likely that all of these sessions will be counted as separate users.
who
supports a few command-line options of interest:
-a
,--all
- Display everything that
who
can output. -b
,--boot
- Output the date and time of the last system reboot.
-H
,--heading
- Output a header line with column titles.
-m
- Only display the hostname and user associated with
who
's standard input. -r
,--runlevel
- Display the current runlevel.
w
Like the who
command, the w
command prints information about users that are logged in, but also displays what they are doing and the system load averages. Specifically, the header includes:
- The current time
- How long the system has been running
- How many users are currently logged on
- The system load averages for the past 1, 5, and 15 minutes
$ w
22:44:19 up 1 min, 1 user, load average: 1.54, 0.86, 0.33
USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT
amnesia :0 :0 22:43 ?xdm? 21.03s 0.00s /bin/sh /usr/lib/gdm3/gdm-x-session
Then, there is one line for every logged-in user, in the manner of who
.
Columnar data includes:
USER
- Login name.
TTY
- The TTY (teletype) name.
FROM
- The remote host.
LOGIN@
- Login time.
IDLE
- Idle time, i.e., the amount of time the user has been doing nothing.
JCPU
- The total CPU time used by all processes in this session (excluding finished background jobs, but including currently-running background jobs).
PCPU
- The CPU time used, so far, by the currently-running process.
WHAT
- The command line of the user's current process.
If you specify a user name as an argument for w
, then only information about that user will be output.
Helpful options include:
-h
,--no-header
- Suppress the header line.
-s
,--short
- Use the short format, i.e., do not print the login time, JCPU, or PCPU times.
last
The last
command searches the /var/log/wtmp
file and displays a list of all users logged in (and out) since /var/log/wtmp
was created.
$ last
amnesia :0 :0 Tue Aug 4 22:43 still logged in
reboot system boot 5.7.0-1-amd64 Tue Aug 4 22:42 still running
wtmp begins Tue Aug 4 22:42:46 2021
One or more login names and/or ttys can be provided to last
to only view entries for those login names.
The output last
produces includes the user, the terminal (or :0
, i.e., the graphical screen, specifically the first X server), the remote end, the start date and time, the end time, and the session duration for every session. If the session end time is crash
, then the computer did not have the opportunity to log the actual end of the session (which may happen with virtual machines).
The reboot
lines refer to system reboots, and in those cases, the third column (where the remote end of the session would otherwise be displayed) gives the name of the operating system kernel being booted.
The information output of last
can be viewed as sensitive. It lets you retroactively check who was logged on where and when, which is sometimes useful for debugging, but could be a cause of concern. It is probably best to be cautious and not keep this data for too long.
If you do not want anyone to be able to read this file with the last
command, run # chmod o-r '/var/log/wtmp'
, which removes read permissions for Other.
faillog
For GNU/Linux distributions like Debian, the faillog
command displays the contents of the failure log database (/var/log/faillog
), which shows failed authentication attempts. It can also be used to set failure counters and limits.
For example, the following command sets a maximum number of failed login attempts before disabling user accounts using the -m
(--maximum
) option:
# faillog -m ex_number
The -l ex_seconds
(--lock-secs ex_seconds
) and -u
(--user
) options are used to lock an account for ex_seconds
after a failed login:
# faillog -l ex_seconds -u ex_username
If your system is using systemd for its initialization system and you have the audit subsystem engaged (run man 8 systemd-journald-audit.socket
and check out the Linux Audit Project for more information), you can run the following command as an alternative to view failed login attempts:
journalctl -q _AUDIT_TYPE=1112 _TRANSPORT=audit | grep 'failed'
Every audit subsystem message type has an associated _AUDIT_TYPE
. Above, the 1112
_AUDIT_TYPE
corresponds to AUDIT_USER_LOGIN
.
pkill
The pkill
command can be used to brute-force log out a user(s):
# pkill -SIGKILL -u ex_username...
The -u
(--euid
) option can be provided a comma-separated list of values as arguments.
If the /etc/nologin
file exists, no one but the root user can log into the system. This behavior is configured in the /etc/pam.d/login
file. The line that reads auth requisite pam_nologin.so
causes PAM to check and see if a file named nologin
exists in /etc/
.
lsof
lsof
lists open files belonging to all active processes on a system:
# lsof
You can give lsof
an object as an argument to narrow down your search, as well (e.g., # lsof ex_name...
, where ex_name
is a file system object).
An open file may be a regular file, a directory, a block special file, a character special file, an executing text reference, a library, a stream, or a network file (e.g., Internet socket, NFS file, or UNIX domain socket).
Options of interest include:
-s
- Display file sizes at all times.
-t
- Specify that
lsof
should produce terse output with process identifiers only and no header. -u ex_user...
- Display only open files associated with the specified user.
ex_user
can be a username or UID, and multiple values can be specified via a comma-separated list (e.g.,ex_user_1,ex_user_1
).
fuser
Sometimes, you may want to find out which process or user is currently using some resource on the system. fuser
identifies processes using files or sockets:
fuser ex_file_or_file_system...
Useful options include:
-a
,--all
- Show all files specified on the command line. By default, only files that are accessed by at least one process are shown.
-k
,--kill
- Kill processes accessing the file.
-i
,--interactive
- Ask the user for confirmation before killing a process. Used with the
-k
option. -m ex_file_or_file_system
,--mount ex_file_or_file_system
ex_file_or_file_system
specifies a file on a mounted file system or a block device that is mounted. All processes accessing files on that file system are listed.-n ex_name_space
,--namespace ex_name_space
- Select a different name space.
ex_name_space
can befile
(the default),tcp
, orudp
. For ports, either the port number or symbolic name may be specified. -u
,--user
- Append the username of the process owner to each PID.
The following example passes in the home directory of the amnesia
user as an argument for fuser
:
$ cd '/home/amnesia'
$ "$(echo hello; sleep 600)" > 'test.txt'
Then, in a different terminal:
$ fuser `/home/amnesia` `/home/amnesia/test.txt`
/home/amnesia: 767c 1360c 1465c 1467c 1488c 1489c
/home/amnesia/test.txt: 1488 1489
fuser
's output is, by default, a list of PIDs followed by a letter that specifies how the process in question is using the resource. The possible letters are:
c
Current directory.e
Executable being run.f
Open file.f
is omitted in the default display mode.F
Open file for writing.F
is omitted in the default display mode.r
Root directory.m
mmap'ed file or shared library..
Placeholder..
is omitted in the default display mode.
The -v
(--verbose
) option gives you more complete output:
$ fuser -v '/home/amnesia/test.txt'
USER PID ACCESS COMMAND
/home/amnesia/test.txt: amnesia 1488 F.... bash
amnesia 1489 F.... sleep
The ACCESS
column uses the codes from the table described above.
The -m
option widens the search from the named file or directory to some file or directory on the same file system as the named file or directory. For example, the command # fuser -m '/srv'
will list all processes that access any file (or directory) on the file system where /srv
resides. This is extremely useful if, on your system, /src
is on its own file system and you would like to unmount it.
To be able to more efficiently deal with situations where you need to unmount a file system, but GNU/Linux will not let you, you can use the -k
option to send a signal (SIGKILL
by default, unless you specify otherwise) to the processes in question (e.g., # fuser -mk -SIGTERM '/srv'; sleep 10; fuser -mk '/srv'
leaves the process ten seconds to gracefully exit, after which they, or whichever processes are left, get forcefully killed.
If you add the -w
option, only those processes that write to the resource(s) will be terminated. With -i
, you will be asked, for every process, whether you really want to kill it or not.
fuser
will not only identify the users of files, but also those of TCP and UDP ports:
# fuser -n tcp ssh
ssh/tcp: 428 912 914
The -n ex_name_space
option chooses the name space, after which you may specify port numbers or symbolic port names (from /etc/services
). As long as there is no ambiguity, you may leave off the -n
option and specify port numbers in the ex_service_port_or_name/ex_name_space
format (e.g., # fuser 80/tcp
), as well.
fuser
for TCP and UDP ports works best as the root user. Usually, ordinary users do not have access to the required data structures.
shred
The shred
command overwrites a file to hide its contents and can optionally delete it (using the -u
option).
shred ex_file...
If the argument provided to shred
is a dash -
, it instructs the command to shred the standard output (e.g., shred - > ex_file
).
If you want shred
to recursively overwrite and delete files in a directory tree, you can do so with the following command:
find ex_directory -type f -exec shred -u {} +
Pretty Good Privacy (PGP)/GNU Privacy Guard (GPG)
GNU Privacy Guard (GPG) is an implementation of the OpenPGP standard RFC4880, which is based on a program called Pretty Good Privacy (PGP) by Phil Zimmermann. GPG allows you to encrypt and sign files and email messages.
An encrypted file is a file containing data that is scrambled in such a way that only authorized people can view or process it. Authorized people have to decrypt the file with the correct key in order to access it.
By signing data, you can document the fact that you created or approved of the data. When the data are changed afterwards, the signature becomes invalid. GPG signatures are an inherent part of package management tools like APT and DNF, i.e., they play an important role in the verification of package data in GNU/Linux distributions.
It is up to you to access the value of digital GPG signatures. For example, Debian developers have to sign their packages before uploading them to the Debian FTP server, where they are accessible by the public.
The signature does not tell you anything about the quality of the package. Its only purpose is to make sure that the developers themselves uploaded the packages and that no malicious packages were introduced to the software collection by third parties.
GNU Privacy Guard (GPG) Configuration
GPG keeps its configuration files in the ${HOME}/.gnupg/
directory. Some of the files that can typically be found in that directory include:
dirmngr.conf
- The standard configuration file read by
dirmngr
(i.e., the Certificate Revocation List (CRL) and Online Certificate Status Protocol (OCSP) daemon) on startup.dirmngr
takes care of accessing the OpenPGP keyservers. - Keyservers can be specified in this file with the
--keyserver ex_keyserver_name
option. gpg.conf
- This file contains various options and parameters used by
gpg
. If it does not exist, you will need to create it. -
Some parameters that you might want to set in
gpg.conf
include:default-key ex_user_id
- Sets the default signing key.
group ex_group
- Defines groups that can save time when encrypting files. For example, imagine the following entry in your
gpg.conf
filegroup beatles = john paul 0x12345678 ringo
(when you specify the--recipient beatles
option, GPG interprets this as three individual--recipient
options with names and one with a key ID). - Groups only work one level deep, i.e., you cannot have groups that contain other groups.
keyserver ex_keyserver
- Specifies your favorite keyserver, e.g.,
keyserver hkp://keys.gnupg.net
. no-greeting
- Suppresses the copyright notice that is initially printed by
gpg
.
pubring.gpg
- The ring of public keys. This file contains the public keys that you have generated or imported.
random_seed
- This file is used by GPG to keep track of the state of the random number generator.
secring.gpg
- The ring of secret keys. This file contains the private keys of your key pairs.
trustdb.gpg
- This file contains the owner trust levels of the keys on your public key ring. Since these are private data reflecting your personal views, they are kept in a separate file and not in the public key ring file (which you may want to make available to others).
GPG is an important program, but it is not straightforward. A good starting point is to study its documentation, which you can view by running man 1 gpg
. More extensive documentation can be found at https://www.gnupg.org/.
Symmetric and Asymmetric Cryptography
Cryptography is a method for encrypting and decrypting data. Basically, there are two approaches to cryptography.
- Symmetric cryptography
- Asymmetric cryptography
Symmetric Cryptography
Symmetric cryptography uses the same key for encrypting and decrypting data. When a hypothetical Diana and Bruce wish to exchange private data using a symmetric method, they have to invent a key first. The same key has to be known to both of them.
When Clark enters the picture, three different keys are needed:
- One for communication between Diana and Bruce
- One for Diana and Clark
- One for Bruce and Clark
Four parties need 6 keys, ten parties need 55 keys, one hundred parties need 5,050 keys, and so on. All of the keys are secret, so they have to be distributed in such a way that no third party can come to know them.
The major issue with symmetric cryptography is key distribution. First, keys have to be transmitted in a secure way, so cryptography would be useful for distributing them in the first place. Second, on the Internet, with billions of potential users, the number of keys required for every user to be able to confidentially communicate with every other user would be astronomical, so much so that possibly no other data could be stored.
These problems are addressed by asymmetric cryptography.
Asymmetric Cryptography (Public-Key Cryptography)
Asymmetric cryptography (Public-Key Cryptography) uses different keys for encrypting and decrypting data. A set of asymmetric keys is called a key pair.
Each key pair consists of a public key and a private key. The public key can safely be made public, while the private key must be kept secret. Now, Diana can privately send content to Bruce by encrypting it with Bruce's public key. Bruce then uses his private key to decrypt the content. Since only Bruce knows his private key, the content is safe during transmission.
Virtually all known asymmetric cryptographic methods are too slow and cumbersome to use to transfer large amounts of private data. This is why asymmetric methods are often used to exchange the keys used to encrypt and decrypt data symmetrically (symmetric cryptography is fast and efficient, and can easily process vast amounts of data).
Private/public key pairs should be much longer than those used for symmetric encryption.
Signatures
Signatures work the other way around. Diana signs content by encrypting it with her private key. Bruce can verify that Diana signed the content by decrypting it with Diana's public key. When the decryption results in consistent data, the content must have been signed using Diana's private key.
Verifying Public Key Authenticity and the Web of Trust
Asymmetric cryptography solves the problem of key distribution, but introduces another problem. How does Bruce know that the key that he uses to verify Diana's signature is really Diana's public key? What is missing in this process is a means of verifying the authenticity of public keys.
The Secure Shell sidesteps this problem by letting the user authenticate the keys. Whenever the ssh
program contacts an unknown server, it asks whether you want to include its public key in your list of known hosts. At this point, it is up to you to verify the authenticity of the key presented to you.
The Secure Sockets Layer (SSL) and Transport Layer Security (TLS) infrastructures as used by secure web sites solve this problem by introducing a hierarchy of certification authorities.
The entire construct is called a public key infrastructure (PKI). The certification authorities assert that a specific key belongs to a specific person and attest to this claim by means of a digital signature. A set consisting of a public key (the owner of a digital signature), and the signature and name of the certification authority is called a certificate.
As a user, you can verify the signature on the certificate using the certification authority's public key (which you have obtained from a trustworthy source; typically, the most important ones come from your web browser). For example, to view the trusted certificate authorities for version 78 of the Firefox ESR (extended support release) web browser, you can navigate to Preferences > Privacy & Security > Certificates > View Certificates....
The question of whether or not you trust the signature on a given certificate comes down to the question of whether or not you trust the people and the work of the certification authority (1, 2, 3).
GPG deliberately does not use the hierarchical structure explained above. It uses an approach that is known as the web of trust.

In the web of trust, there are no central certification authorities that all users must trust. Instead, the concept assumes that users of GPG sign the public keys of people they personally know, thereby documenting that the key belongs to a specific person.
For example, assume that you want to send a private message to Clark, whom you do not know in person. Somewhere, you dig up a public GPG key that claims to be Clark's.
Whether you can trust this key or not depends on the question of whether you or your GPG program can form a chain of trust from yourself to the key in question. When all signatures in a chain of trust are valid, you can assume, with reasonable certainty, that the key of Clark actually belongs to Clark, i.e., it is valid.
GPG supports a concept called owner trust. For each public key that you have available, you can set the degree of pedantry you believe their owners apply when they are dealing with GPG keys.
There are four trust levels:
unknown
Nothing is known about the owner's judgment in key signing. Keys on your public keyring that you do not own initially have this trust level.none
The owner is known to improperly sign other keys.marginal
The owner understands the implications of key signing and properly validates keys before signing them.full
The owner has an excellent understanding of key signing, and their signature on a key would be as good as your own.
Keep in mind, trust levels should not depend on how much you care for a person, but only how much they care about GPG keys.
GPG will consider a public key valid
if it meets two conditions:
-
It is signed by enough valid keys, meaning:
- You have personally signed it.
- It has been signed by one fully trusted key, or
- It has been signed by three marginally trusted keys, and
-
The path of signed keys leading from the public key to your own key is five steps or shorter.
More information on GPG and the web of trust can be found in the The GNU Privacy Handbook.
As a GPG user that wants to take part in the web of trust, you should abide by several rules. Most importantly, you should sign other people's keys only if you are absolutely positive about their identity. When in doubt, ask the person for a piece of official photo identification (or two). Never sign keys based on hearsay.
In principle, you do not need your own GPG key pair in order to send encrypted messages to other people or to verify their signatures. All you have to do is to obtain the public keys in question. However, a successful signature check merely indicates that a file has not been tampered with.
To verify that the signature was generated by the person who claims to have created it, you have to take part in the web of trust. This is the only way to make sure that a signature is valid
, according to the rules previously outlined.
So, the first step to seriously using GPG is the generation of your own key pair (when you use GPG to check the integrity of distribution packages, your distributor normally ships a set of public keys that can be used for verification).
Generating an Asymmetric Key Pair
A key pair is generated by running the gpg
program with the --full-generate-key
option:
$ gpg --full-generate-key
gpg (GnuPG) 2.2.12; Copyright (C) 2018 Free Software Foundation, Inc.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Please select what kind of key you want:
(1) RSA and RSA (default)
(2) DSA and Elgamal
(3) DSA (sign only)
(4) RSA (sign only)
Your selection? 1
RSA keys may be between 1024 and 4096 bits long.
What keysize do you want? (3072) 4096
Requested keysize is 4096 bits
The default option, RSA and RSA
generates two key pairs:
- A RSA key pair for signing data.
- A RSA key pair for encrypting and decrypting data.
Next, you have to assign a life time to the key. You can change the life time of the key afterwards, but in this case you will have to redistribute the key in order to make this change known to the public.
Please specify how long the key should be valid.
0 = key does not expire
<n> = key expires in n days
<n>w = key expires in n weeks
<n>m = key expires in n months
<n>y = key expires in n years
Key is valid for? (0) 0
Key does not expire at all
Is this correct? (y/N) y
The next step is to assign a User ID to your key. This ID consists of a name, an email address, and an optional comment:
GnuPG needs to construct a user ID to identify your key.
Real name: amnesia
Email address: amnesia@example.org
Comment:
You selected this USER-ID:
"amnesia <amnesia@example.org>"
Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? O
Finally, you have to specify a passphrase that will be used to encrypt your private key. A good passphrase is essential to the security of GPG. It is your only protection should the key pair, especially the private key, ever fall into the wrong hands.
In the last step, the key pairs themselves will be generated. This step requires high-quality random numbers. GNU/Linux generally generates those numbers by measuring the times between I/O events, like key presses and movements of the mouse.
We need to generate a lot of random bytes. It is a good idea to perform
some other action (type on the keyboard, move the mouse, utilize the
disks) during the prime generation; this gives the random number
generator a better chance to gain enough entropy.
We need to generate a lot of random bytes. It is a good idea to perform
some other action (type on the keyboard, move the mouse, utilize the
disks) during the prime generation; this gives the random number
generator a better chance to gain enough entropy.
gpg: key 749DDC030A1077C7 marked as ultimately trusted
gpg: revocation certificate stored as '/home/amnesia/.gnupg/openpgp-revocs.d/72F6EECB923CA1DE8F762FE6749DDC030A1077C7.rev'
public and secret key created and signed.
pub rsa4096 2020-10-02 [SC]
72F6EECB923CA1DE8F762FE6749DDC030A1077C7
uid amnesia <amnesia@example.org>
sub rsa4096 2020-10-02 [E]
Creating a Revocation Certificate
Often, it is wise to create a revocation certificate, which can be used to declare a public key invalid in case the corresponding private key is compromised or lost. The revocation certificate states that the key that it invalidates should no longer be used to encrypt data. The revoked key can still be used for verifying existing signatures.
In the key generation example above, a revocation certificate was automatically created during the key generation process. However, you can also manually create a revocation certificate.
A revocation certificate is created using the -o ex_file
(--output ex_file
) and --gen-revoke
options:
$ gpg -o 'revoke.asc' --gen-revoke 'amnesia'
sec rsa4096/749DDC030A1077C7 2020-10-02 amnesia <amnesia@example.org>
Create a revocation certificate for this key? (y/N) y
Please select the reason for the revocation:
0 = No reason specified
1 = Key has been compromised
2 = Key is superseded
3 = Key is no longer used
Q = Cancel
(Probably you want to select 1 here)
Your decision? 1
Enter an optional description; end it with an empty line:
> My private key was stolen.
>
Reason for revocation: Key has been compromised
My private key was stolen.
Is this okay? (y/N) y
ASCII armored output forced.
Revocation certificate created.
Please move it to a medium which you can hide away; if Mallory gets
access to this certificate he can use it to make your key unusable.
It is smart to print this certificate and store it away, just in case
your media become unreadable. But have some caution: The print system of
your machine might store the data and make it available to others!
At this point, you will be asked for your key's passphrase. After entering it, the revocation certificate will be stored in the file revoke.asc
in the current directory.
The revocation certificate generated here is intended for use in a worst-case scenario, i.e., for the case where your key becomes permanently unusable. If you decide to revoke your key for a different reason some day, feel free to create a fresh revocation certificate that more accurately reflects your reason.
The revocation certificate should be stored on a medium that you can lock away, and not on your computer. When an attacker gets their hands on the certificate, they can use it to make your key unusable. It may be wise to store a printed copy of the certificate, too, so that you can type it in by hand, if necessary.
Exporting and Publishing a Public Key
The next step would be to publish your public key in order to make it available. To do so, you will have to export the key first.
The -k
(--list-public-keys
) option makes GPG list all public keys that you can use:
$ gpg -k
gpg: checking the trustdb
gpg: marginals needed: 3 completes needed: 1 trust model: pgp
gpg: depth: 0 valid: 1 signed: 0 trust: 0-, 0q, 0n, 0m, 0f, 1u
/home/amnesia/.gnupg/pubring.kbx
------------------------------
pub rsa4096 2020-10-02 [SC]
72F6EECB923CA1DE8F762FE6749DDC030A1077C7
uid [ultimate] amnesia <amnesia@example.org>
sub rsa4096 2020-10-02 [E]
Above, the 72F6EECB923CA1DE8F762FE6749DDC030A1077C7
value is the key's fingerprint and the last eight (or sixteen) characters of this value are the key's key ID.
Your public key is exported by the --export
option of GPG. As in the command creating the revocation certificate, the -o
option can be used to specify a filename to which the output will be written. The -a
(--armor
) option generates output in ASCII format, so that it can be sent via email or published on a web site:
$ gpg -o 'amnesia.gpg' -a --export 'amnesia'
$ cat amnesia.gpg | head
-----BEGIN PGP PUBLIC KEY BLOCK-----
mQINBF93iLABEAC3cq/PoC2VnOGGh622Rvj27ctYZMdz9H8u5RUoU365//S7X0QJ
GhdsYsf6QV/EWbhHDfPeqdZKB/0EMWT/PNJqPMpV0xD/ekyEpn49JtfIlOYiphJe
HQCEyaV76RCAZVfrTngcRUlCQzLXBz+3L2SpZK9XtD3iFlLZlRxDzgKVc8IcNyFn
QLxuJWuUScMa4UaGigelPfIET1F9u0kI7tO36tp9HuT2nO1h7Rx05yVpSFNCTIdV
Dp5WCHbMkOdgSd8bQWWTrcWlSiXSs00P5+c9tjU3fxjHiOQ8tG5lvv7pACcfefLp
WSMfj8w6i0APwiBJAFd0xyn9Gm2XzXlgpKaVHdQIt0+/Na0fHdB5NYkUwsAwD+Y9
E12fqNO5QBK/gi5QQuNFQt4TdfRPmwX/KtTKNs/OnfSJq9zqojAL+Smfuluv/rhQ
KSf1eFVB9GZ8MMGSC/1PD7JQEb0ouBPHouAmhkM5Jcd/MSvfMU14GvmFdR8iWRoT
A more efficient way of publishing your public key is to upload it to a key server. This is also done with the help of the gpg
program, e.g., gpg --keyserver 'hkp://subkeys.pgp.net' --send-keys '0A1077C7'
. Most key servers synchronize their data, so it is normally sufficient to upload your key to only one of them.
Instead of specifying a keyserver on the command line with --keyserver
, you can specify a default gpg
keyserver in your ${HOME}/.gnupg/dirmngr.conf
file by adding a line like so:
--keyserver ex_keyserver_name
A list of common keyservers can be found in the ArchWiki.
Importing a Public Key
When you find a public key in an email message or on a web site, you will have to import it into your key ring before you can use it:
$ gpg --import '249CB3771750745D5CDD323CE267B052364F028D.asc'
gpg: key E267B052364F028D: public key "NIIBE Yutaka <gniibe@fsij.org>" imported
gpg: Total number processed: 1
gpg: imported: 1
$ gpg -k
/home/amnesia/.gnupg/pubring.kbx
------------------------------
pub ed25519 2015-08-12 [SC]
249CB3771750745D5CDD323CE267B052364F028D
uid [ unknown] NIIBE Yutaka <gniibe@fsij.org>
uid [ unknown] NIIBE Yutaka <gniibe@debian.org>
sub ed25519 2015-08-12 [A]
sub cv25519 2015-08-12 [E]
Verifying a Public Key (Fingerprint)
Now, the new key is part of your key ring, but you still need to verify that it is authentic. It is best to generate the fingerprint of the key and ask the key owner whether it is correct:
$ gpg --fingerprint 'NIIBE Yutaka'
pub ed25519 2015-08-12 [SC]
249C B377 1750 745D 5CDD 323C E267 B052 364F 028D
uid [ unknown] NIIBE Yutaka <gniibe@fsij.org>
uid [ unknown] NIIBE Yutaka <gniibe@debian.org>
sub ed25519 2015-08-12 [A]
sub cv25519 2015-08-12 [E]
You may consider printing the fingerprint of your GPG key on your business card or prepare some slips of paper containing the key data. This way, when you meet a person and want to swap signatures, you can hand them a copy of the fingerprint and, if necessary, identify yourself.
Then, the other person can fetch your public key from a key server and use the fingerprint to make sure that the key really belongs to you. Finally, they can sign the key and send you a copy, so that you can integrate the signature into your official public key (i.e., you import your newly signed public key into your keychain, and then re-submit the public key to your key server of choice).
Another popular means of verifying keys are key signing parties where, for example, members of open source projects perform mutual mass verification of their GPG keys. The user IDs and public key fingerprints of all participants are collected and distributed to all persons taking part in the event.
Afterwards, every participant checks the ID of each person on the list and marks the keys that they are willing to trust. Once the lists are complete, the keys can be later signed.
For example, say that you have successfully verified the authenticity of Yutaka's public key. Now, you can sign Yutaka's key. Yutaka benefits from your signing their key because their key is now considered to be valid by all people who consider your key to be valid.
You benefit from signing the key, too, because you are now connected to Yutaka's web of trust. You can assume that keys that have been signed by Yutaka are valid, too.
Owner trust also plays a role. In your key ring, you can make a note of the degree to which you trust Yutaka's knowledge of GPG and their diligence in handling keys. This note affects the validity of keys signed by Yutaka.
When you are not sure about Yutaka's skills, keys signed by Yutaka will have to be signed by other people in your web of trust in order to become valid. When you trust Yutaka fully, their signature alone is sufficient.
You can sign Yutaka's key as follows:
gpg --sign-key 'NIIBE Yutaka'
After you confirm that you want to sign Yutaka's key, gpg
once more prompts for your key's passphrase.
The signatures on a key can be listed and checked at the same time by using the --check-signatures
option:
$ gpg --check-signatures 'NIIBE Yutaka'
pub ed25519 2015-08-12 [SC]
249CB3771750745D5CDD323CE267B052364F028D
uid [ unknown] NIIBE Yutaka <gniibe@fsij.org>
sig!3 E267B052364F028D 2015-08-13 NIIBE Yutaka <gniibe@fsij.org>
uid [ unknown] NIIBE Yutaka <gniibe@debian.org>
sig!3 E267B052364F028D 2015-08-12 NIIBE Yutaka <gniibe@fsij.org>
sub ed25519 2015-08-12 [A]
sig! E267B052364F028D 2015-08-12 NIIBE Yutaka <gniibe@fsij.org>
sub cv25519 2015-08-12 [E]
sig! E267B052364F028D 2015-08-12 NIIBE Yutaka <gniibe@fsij.org>
gpg: 4 good signatures
An exclamation mark after the sig
at the beginning of a line indicates that the signature was successfully verified. When a signature is bad, there would be a minus sign -
, instead.
All of the above signatures can be checked by you because you own copies of all of the required public keys. When a signature cannot be checked because a public key is lacking, that signature will be ignored.
The gpg --list-signatures
command lists all signatures without checking them. Signatures with missing public keys will appear as [User-ID not found]
.
Managing Keys
For managing keys, you can use the --edit-key
option:
$ gpg --edit-key 'NIIBE Yutaka'
gpg (GnuPG) 2.2.12; Copyright (C) 2018 Free Software Foundation, Inc.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
pub ed25519/E267B052364F028D
created: 2015-08-12 expires: never usage: SC
trust: unknown validity: unknown
sub ed25519/5F910521FAA805B1
created: 2015-08-12 expires: never usage: A
sub cv25519/850AF040D619F240
created: 2015-08-12 expires: never usage: E
[ unknown] (1). NIIBE Yutaka <gniibe@fsij.org>
[ unknown] (2) NIIBE Yutaka <gniibe@debian.org>
gpg>
At the gpg>
prompt, you can enter commands. For example, fpr
lists the fingerprint of a key and sign
signs a key. There are many other commands. help
prints a summary.
An important command is trust
, which changes the owner trust level:
gpg> trust
pub ed25519/E267B052364F028D
created: 2015-08-12 expires: never usage: SC
trust: unknown validity: unknown
sub ed25519/5F910521FAA805B1
created: 2015-08-12 expires: never usage: A
sub cv25519/850AF040D619F240
created: 2015-08-12 expires: never usage: E
[ unknown] (1). NIIBE Yutaka <gniibe@fsij.org>
[ unknown] (2) NIIBE Yutaka <gniibe@debian.org>
Please decide how far you trust this user to correctly verify other users' keys
(by looking at passports, checking fingerprints from different sources, etc.)
1 = I don't know or won't say
2 = I do NOT trust
3 = I trust marginally
4 = I trust fully
5 = I trust ultimately
m = back to the main menu
Your decision?
The difference between full
and ultimate
is the difference between others and yourself. You might trust other people's keys fully, but should only trust your own keys ultimately.
The trust database of GPG is updated only when the program is started for the next time, so when you plan to change multiple trust levels, you should do this in a single session and then restart gpg
.
Revoking a Public Key
If you ever want to revoke your public key, you have to first import the revocation certificate to your key ring:
gpg --import 'revoke.asc'
Then, you can send the revoked key to the usual key servers.
Encrypting Content
Content can be encrypted using symmetric or asymmetric cryptography.
Encrypting Content With Asymmetric Cryptography
In order to asymmetrically encrypt a file using GPG, you need the public key of the recipient of the file. A file can be encrypted via the -e
(--encrypt
) and -r
(--recipient
) options:
gpg -e -r ex_name ex_input_file
This command encrypts the file ex_input_file
, such that only ex_name
can read it. The encrypted version is created as a separate file, ex_output_file.gpg
, in the current directory.
You can also use the -a
(--armor
) option to create an ASCII version of the encrypted message, which can be pasted into an email message. Furthermore, you can encrypt a message in such a way that multiple recipients can read it.
To do so, specify one -r
option for each recipient. Note that this is implemented by including an individually encrypted copy for each recipient in the output file.
The encrypted file can be decrypted via use of ex_name
's private key and the -d
(--decrypt
) option:
gpg -d ex_output_file.gpg
By default, gpg
sends the decrypted content to the standard output, but you could save it as a separate file using the -o
option (gpg -o ex_output_file -d ex_output_file.gpg
).
The passphrase for ex_name
's private key will need to be entered.
Encrypting Content With Symmetric Cryptography
If you wish to encrypt a file that you just want to keep to yourself, you do not need asymmetric cryptography. gpg
's -c
(--symmetric
) option uses a symmetric key that is derived from a passphrase that you specify. The same passphrase is used to decrypt the file:
$ echo 'Hello World!' | gpg -o 'secret.gpg' -c
Enter passphrase: foobar
Repeat passphrase: foobar
$ gpg -d 'secret.gpg'
gpg: AES256 encrypted data
Enter passphrase: foobar
gpg: encrypted with 1 passphrase
Hello World!
The above example demonstrates how GPG reads encrypted data from the standard input stream and writes decrypted data to the standard output stream.
Digitally Signing Content
You can also use your key pair to sign a file. Signing a file annotates the content of the file with a time stamp and a digest.
When the file is modified after signing it, verifying the signature will fail. This mechanism is used to sign software packages of distributions, thereby allowing you to verify that it was the maintainer of a package who uploaded it, and not a malicious attacker.
You can be reasonably sure that properly signed packages will not introduce any malware, like viruses or trojans. You can also use a signature to sign a manuscript when sending it to your publisher, so that they can be sure that they receive the original work, and not a tampered with copy.
A side effect of this approach is that it is difficult for you to claim that a document with your digital signature was not signed by yourself. This would imply that your private key has been compromised.
There is a certain tendency toward giving digital signatures as created by GPG the same legal status as a signature on a sheet of paper. This is unfortunate or even dangerous, because there is a considerable difference between the act of signing your name on a piece of paper, and the act of typing a passphrase and pressing Enter.
On a sheet of paper, you sign exactly what is written on that sheet and nothing else. In cases of doubt, there is a strong presumption that you meant what you signed.
When signing a digital document, there is no guarantee that the computer really signs exactly the intended document (and only that document and not simultaneously, say, a purchase agreement). This is why in a legal dispute, destroying the claim that a digital signature is equal to a real-life signature should be facile for a competent expert.
To sign a file with GPG, run gpg
with the -s
(--sign
) option:
gpg -o ex_output_file.sig -s ex_input_file
Here, ex_output_file.sig
represents the ex_input_file
file with an incorporated GPG signature.
Since the file is signed with your private key, you have to enter your key's passphrase. The signed file will be compressed, as well. It is written to the output file in binary format.
You can verify a signature with gpg
's --verify
option:
$ gpg --verify 'text.txt.sig'
gpg: Signature made Thu Feb 18 11:22:33 2016 CET using DSA key ID ed25519
gpg: Good signature from "NIIBE Yutaka <gniibe@fsij.org>"
gpg -d
checks the signature, decompresses the file, and writes it to the standard output:
$ gpg -d 'text.txt.sig'
Hello World!
gpg: Signature made Thu Feb 18 11:22:33 2016 CET using DSA key ID ed25519
gpg: Good signature from "NIIBE Yutaka <gniibe@fsij.org>"
As usual, the -o
option can be used to write the decompressed data directly to a file.
The compressed binary format is not practical for including in email messages. In this case, you would use the --clearsign
option instead, which generates a plain text version of its output. The resulting file contains both the signed data and the signature in ASCII format:
gpg --clearsign ex_file
Such a file looks like this:
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
Hello World!
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.7 (FreeBSD)
psvOnpEbJkzRK2mavQQFyllXkkxKVk44buyNuCHeyr8ybFCOvmIAs23GbmgzrqFU
X9WSkdCNpjCs2Cdkn5yp2uls=
=UH8U
-----END PGP SIGNATURE-----
Plaintext messages are used in the Debian project. The .dsc
files, which accompany source code packages, contain the checksums of the original source code (typically a .tar.gz
file) and the patch containing Debian-specific changes, and are signed by the package maintainer. This allows you to check, upon installing a package, that the version you have is in fact created by the package maintainer.
Similarly, a new version of a package that is to be available on the Debian servers as part of a distribution must be accompanied by a GPG-signed .changes
file listing the files the package consists of, together with their checksums. Files that are uploaded without a .changes
file signed by a Debian developer will be discarded.
Sometimes, you may want to sign a file without changing it by adding the signature. For example, this is required, when submitting a package to a GNU/Linux distributor or when you want to guarantee the authenticity of a source code archive that you are publishing.
When annotating a tar
archive with a signature, it would no longer be a valid tar
archive, so you have to keep the signature in a separate file. This is called a detached signature.
In order to create a detached signature, use the -b
(--detach-sign
) option of gpg
:
gpg -o ex_output_file.sig --detach-sign ex_input_file
Here, ex_output_file.sig
does not represent the ex_input_file
file. It is just a detached GPG signature.
To verify a file using a detached signature, you need the signature and the signed file to be in the same directory. The --verify
option of gpg
also verifies detached signatures:
gpg --verify ex_file.sig ex_file
The first file name following --verify
is the name of the file containing the detached signature and the second file specifies the file associated with the detached siganture.
When only one file name is passed to --verify
(e.g., gpg --verify ex_file.sig
), the program assumes that the name specifies the name of the detached signature file, and that the name of the signed file is identical (but without the .sig
suffix). When the -a
option is used, gpg
removes the .asc
suffix, instead of .sig
, in order to determine the name of the actual signed file.
The Pretty Good Privacy (PGP) / GNU Privacy Guard (GPG) Process
Often, GPG is used to securely send email messages. This process uses both asymmetric and symmetric cryptography.
On the sender's side:
- The plaintext message is hashed and the resulting checksum is digitally signed (encrypted) with the sender's private key (i.e., an encrypted checksum is created).
- The plaintext message and the signed checksum are combined/compressed, and then encrypted with a symmetric key that the sender randomly generates.
- The symmetric key is encrypted with the receiver's public key and is combined with the previously encrypted content.
On the receiver's side:
- The sender's symmetric key is decrypted with the receiver's private key.
- The decrypted symmetric key is used to decrypt the ciphertext message and the signed checksum. This leaves the receiver with the plaintext message and the signed checksum.
- The sender's public key is used to verify (decrypt) the signed checksum. The recipient generates their own hash (i.e., checksum) of the decrypted message and compares it to the decrypted checksum from the sender.
Regarding the use of asymmetric cryptography in this process, notice that when it comes to digital signatures, the private key is used for encryption and the public key is used for decryption. Yet, for the randomly generated symmetric key that the sender creates, the inverse is true, i.e., the public key is used for encryption and the private key is used for decryption.
GNU Privacy Guard (GPG) Commands
gpg --generate-key
,gpg --gen-key
- Generate a new key pair using the current default parameters. Key files are stored in
${HOME}/.gnupg/
and a revocation certificate is created and stored in the${HOME}/.gnupg/openpgp-revocs.d/
directory. gpg --full-generate-key
,gpg --full-gen-key
- Generate a new key pair with dialogs for all options. This is an extended version of
--generate-key
. gpg --import ex_key_file...
- Import/merge keys. This adds the given keys to the keyring.
ex_key_file
can be a file likeex_key.gpg
,ex_key.txt
, orex_key.key
.gpg --keyserver ex_key_server_url --receive-keys ex_user_id
- Import a public key from a keyserver.
ex_key_server_url
is in the format ofscheme:[//]keyservername[:port]
. -
- There are different ways to specify
ex_user_id
: -
- key ID (
234567C4
,234AABBCC34567C4
,0x234AABBCC34567C4
)
- key ID (
-
- fingerprint (
0E12343434343434343434EAB3484343434343434
)
- fingerprint (
-
- OpenPGP user ID (
=Heinrich Heine <heinrichh@uni-duesseldorf.de>
)
- OpenPGP user ID (
-
- email address (
<heinrichh@uni-duesseldorf.de>
)
- email address (
-
- subject's Distinguished Name (DN) (
/CN=Heinrich Heine,O=Poets,L=Paris,C=FR
)
- subject's Distinguished Name (DN) (
-
- issuer's DN (
#/CN=Root Cert,O=Poets,L=Paris,C=FR
)
- issuer's DN (
-
- serial number and issuer's DN (e.g.,
#4F03/CN=Root Cert,O=Poets,L=Paris,C=FR
)
- serial number and issuer's DN (e.g.,
-
- keygrip (
&D75F22C3F86E355877348498CDC92BD21010A480
)
- keygrip (
-
- substring match (
*Heine
)
- substring match (
-
- . and + prefixes (these are reserved for looking up mails anchored at the end and for a word search mode; they are not yet implemented and using them is undefined)
- There are different ways to specify
-
The key ID is either the last
16
(Long key ID) or8
(Short key ID) characters in the fingerprint. -
The fingerprint is a
160
-bit SHA-1 hash of the octet0x99
, followed by the two-octet packet length, followed by the entire Public-Key packet starting with the version field. The fingerprint for each user ID can be viewed using thegpg -k
command. -
For example, for
0x9026DBBE1FC237AF
, the value after0x
is the Long key ID. The corresponding fingerprint is0BC4700A06E2072D3A77F8E29026DBBE1FC237AF
. -
Out of all the user ID options, the fingerprint is probably the best to use, as it removes any ambiguity. For more information on specifying user IDs, check out the GnuPG documentation.
wget -O - -q ex_key_url | gpg --import
- Import a key from a URL.
gpg --export
- Export all public keys from all keyrings.
- If
export
is provided one or more user IDs (in a space separated list), only those public keys are exported (gpg --export ex_user_id_1 ex_user_id_2
). - Exported public keys are written to the standard output or to the file specified with the
-o
option (gpg -o ex_public_key.pub --export ex_user_id
). gpg -a -o ex_public_key.txt --export ex_user_id
,gpg --armor --output ex_public_key.txt --export ex_user_id
- Generate a plaintext version of a public key.
- The
-a
option creates the ASCII armored output and the-o
option writes the command output to a file. gpg --export-secret-keys
- Export all private keys from all keyrings.
- If
--export-secret-keys
is provided one or more user IDs (in a space separated list), only those private keys are exported (gpg --export-secret-keys ex_user_id_1 ex_user_id_2
). - Exported private keys are written to the standard output or to the file specified with the
-o
option (gpg -o ex_private_key.key --export-secret-keys ex_user_id
). gpg -a -o ex_private_key.txt --export-secret-keys ex_user_id
,gpg --armor --output ex_private_key.txt --export-secret-keys ex_user_id
- Generate a plaintext version of a private key.
- The
-a
option creates the ASCII armored output and the-o
option writes the command output to a file. gpg --keyserver ex_key_server_url --send-keys ex_user_id...
- Export a public key to a keyserver.
ex_key_server_url
is in the format ofscheme:[//]keyservername[:port]
. gpg --delete-secret-and-public-key ex_user_id
- Remove key from the public keyring. If a secret key exists, it will be removed first.
gpg -k
,gpg --list-public-keys
- List all keys from configured public keyrings. A specific key (or keys as a space separated list) can be passed to
-k
as an argument to list only that key(s). - Each key has a role that is represented by a character. These are the roles and their corresponding characters:
Select to view GNU Privacy Guard (GPG) Key Roles
GNU Privacy Guard (GPG) Key Roles Constant Character Explanation PUBKEY_USAGE_SIG
S
Key is good for signing PUBKEY_USAGE_CERT
C
Key is good for certifying other signatures PUBKEY_USAGE_ENC
E
Key is good for encryption PUBKEY_USAGE_AUTH
A
Key is good for authentication -
Keys are marked with
pub
(public) orsub
(public subkey). gpg -K
,gpg --list-secret-keys
- List all known secret keys. A specific key (or keys as a space separated list) can be passed to
-K
as an argument to list only that key(s). - Keys are marked with either
sec
(secret) orssb
(secret subkey). - You can specify the location of a GPG directory with the
--homedir ex_gpg_directory
option, e.g.,--homedir /media/encrypted_usb/.gnupg/
. This is handy if you have your.gnupg/
directory saved someplace other than${HOME}/.gnupg/
. gpg --fingerprint
- List all keys from configured public keyrings, along with their fingerprints. A specific key (or keys as a space separated list) can be passed to
--fingerprint
as an argument to list only that key(s). - If
--fingerprint
is given twice (gpg --fingerprint --fingerprint
), the fingerprints of all secondary keys are listed too. gpg -a -o ex_user_id.asc --gen-revoke ex_user_id
,gpg --armor --output ex_user_id.asc --generate-revocation ex_user_id
- Generate a revocation certificate for the complete key.
- The
-a
option creates the ASCII armored output and the-o
option writes the command output to a file. - You will need to specify a reason for the revocation and enter an optional description (e.g.,
1 = Key has been compromised
andThis revocation certificate was generated when the key was created.
). The revocation file should be stored someplace safe (e.g., on separate encrypted media). It can also be printed. gpg --list-sigs
,gpg --list-signatures
- List all keys from configured public keyrings, along with their signatures. A specific key (or keys as a space separated list) can be passed to
--list-sigs
as an argument to list only that key(s). - The key signatures are not verified.
gpg --check-sigs
,gpg --check-signatures
- List all keys from configured public keyrings, along with their verified signatures. A specific key (or keys as a space separated list) can be passed to
--check-sigs
as an argument to list only that key(s). - A good signature will have a
sig
entry followed by a!
. - A bad signature will have a
sig
entry followed by a-
. - You will already need to have the public key of the signer imported into your keychain to properly perform this check (signatures where the public key is not available are not listed).
gpg -r ex_user_id -e ex_file
,gpg --recipient ex_user_id --encrypt ex_file
- Encrypt a file using a recipient's public key.
ex_user_id
can be an email address. gpg
will create an encrypted version of your file with the.gpg
file extension in the current directory, e.g.,ex_file.gpg
. You can specify the exact name of the output file using the-o
option (gpg -o ex_file.gpg -r ex_user_id -e ex_file
).- You can add the
-s
(--sign
) option to also sign the file (e.g.,gpg -s -r ex_user_id -e ex_file
). You will need to enter your private key's password to sign the file. gpg -r ex_user_id --encrypt-files ex_file_1...
,gpg --recipient ex_user_id --encrypt-files ex_file_1...
- Encrypt multiple files using a recipient's public key. Files are provided as a space separated list.
tar -czf - ex_dir | gpg -o ex_dir.tar.gz.gpg -r ex_user_id -e
,tar -czf - ex_dir | gpg --output ex_dir.tar.gz.gpg --recipient ex_user_id --encrypt
- Encrypt a directory using a recipient's public key.
ex_user_id
can be an email address. - The
-
after-czf
tellstar
to write to the standard output, which is piped to thegpg
command. gpg -c ex_file
,gpg --symmetric ex_file
- Encrypt a file using symmetric encryption. You will need to specify an encryption password.
gpg
will create an encrypted version of your file with the.gpg
file extension in the current directory, e.g.,ex_file.gpg
. You can specify the exact name of the output file using the-o
option (gpg -o ex_file.gpg -c ex_file
).- You can specify the encryption algorithm to use with the
--cipher-algo ex_algorithm
option, e.g.,gpg -c --cipher-algo AES256 ex_file
. Rungpg --version
to view the supported algorithms. tar -czf - ex_dir | gpg -o ex_dir.tar.gz.gpg -c
,tar -czf - ex_dir | gpg --output ex_dir.tar.gz.gpg --symmetric
- Encrypt a directory using symmetric encryption.
- The
-
after-czf
tellstar
to write to the standard output, which is piped to thegpg
command. gpg -d ex_file
,gpg --decrypt ex_file
- Decrypt a file and write it to the standard output.
- You will need to enter the password associated with the key/file. You can write the output to a file using the
-o
option, e.g.,gpg -o ex_output_file -d ex_file
. gpg --decrypt-files ex_file_1...
- Decrypt multiple files. Files are provided as a space separated list.
- You will need to enter the password associated with the files.
gpg -d ex_output.tar.gz.gpg | tar -xf -
,gpg --decrypt ex_output.tar.gz.gpg | tar -xf -
- Decrypt a directory.
- You will need to enter the password associated with the key/directory. The
-
after-xf
tellstar
to use the standard input as the archive to operate on, which is piped in from thegpg
command. gpg --verify ex_file.gpg.asc
,gpg --verify ex_file.gpg.sig
- Assume that the first argument is a file with an incorporated signature and verify it without generating any file content output.
- If more than one argument is given, the first argument should specify a file with a detached signature and the remaining argument should be the file associated with the detached signature.
- The public key of the individual that signed the file should be in your keychain prior to verification.
gpg --verify-files ex_file.gpg.asc...
,gpg --verify-files ex_file.gpg.sig...
- Verify multiple files. Files are provided as a space separated list.
gpg --default-key old_user_id --sign-key new_user_id
- Sign a new key with an old key.
- Afterwards, write a transition statement and sign it with both the old and new key:
$ gpg -a -b -u old_user_id -o sig_1.txt gpg_transition.txt $ gpg -a -b -u new_user_id -o sig_2.txt gpg_transition.txt
-
-a
creates ASCII armored output,-b
(--detach-sign
) creates a detached signature, and-u
(--local-user
) is provided a user ID as the key to sign with.-o
specifies the file to write the output to. -
Finally, upload your transition statement and signatures (i.e.,
gpg_transition.txt
,sig_1.txt
,sig_2.txt
) to a public place.
GPG Command Line Interface (CLI) Commands
The following commands can be used at the gpg>
command prompt after running gpg --edit-key ex_user_id
:
gpg> help
- Display GPG CLI commands.
gpg> adduid gpg> save
-
Add a user ID to a key.
gpg> uid ex_uid_number gpg> primary gpg> save
-
Set a user ID as the primary user ID for a key.
gpg> addkey
- Add a new signing key to a master key.
- After running
addkey
, you will need to choose a(sign only)
option (e.g.,(4) RSA (sign only)
), as well as specify the length of the key (e.g.,4096
), and a length of time before the key expires (e.g.,5y
). - Make sure to run the
save
command after you are done. gpg> revkey gpg> save
-
Revoke a key.
gpg> trust
- Trust a public key.
Documentation
For more on PGP/GPG, run the man 1 gpg
command. Also, in-depth documentation is available online:
Checksums
A checksum a small-sized datum derived from a block of digital data that is used to verify data integrity.
Checksum Commands
sum ex_file...
- Checksum and count the blocks in a file.
shasum ex_file...
- Print or check Secure Hash Algorithm (SHA) checksums.
- You can specify which algorithm to use with the
-a ex_algorithm
(--algorithm ex_algorithm
) option. You will need to pass in a specific algorithm as an argument (e.g.,512
,512224
,512256
). shasum
is a perl script that points to actual GNU/Linux commands, likesha512sum
, that do the work.shasum ex_file > ex_file.sha
- Generate a checksum for a file and save the checksum to a
.sha
file. shasum -c ex_file.sha
,shasum --check ex_file.sha
- Verify the checksum for a file from a
.sha
file. ex_file.sha
andex_file
should be located in the same directory.
Documentation
For more information on checksums, run the following commands:
man 1 sum
man 1 shasum
Secure Shell (SSH)
Secure Shell (SSH) is a Transmission Control Protocol/Internet Protocol (TCP/IP)-based networking protocol. It provides data transmission in a public network using strong authentication and encryption. Its applications include interactive sessions, file transfer, and the secure forwarding of other protocols (i.e., tunneling).
Encryption is important for preventing unauthorized people listening to network traffic from being able to read the content being transferred. Authentication ensures that you, as the user, are communicating with the correct server and that the server lets you access the correct user account.
OpenSSH, which comes with most GNU/Linux distributions, is a freely available implementation of SSH (on Debian, you can install the OpenSSH server with the # apt install openssh-server
command). This implementation contains SSH clients, as well as an SSH server (sshd
).
Used properly, SSH can prevent the following attacks:
- Forged or adulterated DNS entries (DNS spoofing).
- When an attacker sends datagrams from one host, which pretend that they come from another (trusted) host (IP spoofing).
- When a host can pretend that datagrams come from another (trusted) host (IP source routing).
- Sniffing of passwords and content transmitted in the clear on hosts along the transmission path.
- Manipulation of transmitted data by hosts along the transmission path.
- Attacks on the X11 server by means of sniffed authentication data and spoofed connections to the X11 server.
SSH offers a complete replacement for the insecure Teletype Network (TELNET), Remote Login (RLOGIN), and Remote Shell (RSH) protocols. In addition, it enables users to copy files from or to remote hosts, and is a secure replacement for Remote Copy (RCP) and the many applications of File Transfer Protocol (FTP).
There are two versions of the SSH protocol, 1 and 2. Most servers can accept connections using both versions. Avoid using version 1, which exhibits various security vulnerabilities.
OpenSSH
A Certificate Authority (CA) issues public key certificates. A public key certificate is a digital message signed with the private key that provides a cryptographic binding between the public key and the organization that owns the private key.
A certificate contains the following information:
- The name of the organization
- The public key of the organization
- The expiration date of the certificate
- The certificate's serial number
- The name of the CA that signed the certificate
- A digital signature from the CA
There are two types of CAs:
- Internal CA (OpenSSL, the library that OpenSSH relies on, is used to create a CA on your system)
- External CA
OpenSSH provides the following encryption-enabled components:
sshd
Allows remote access to the shell prompt.ssh
Thessh
client used to connect tosshd
on another system.scp
Used to securely copy files between systems.sftp
Used to securely FTP files between systems.slogin
Used to access the shell prompt remotely (slogin
is just a symbolic link tossh
).
System-Specific SSH Configuration
The SSH configuration directory is located at /etc/ssh/
. Its permissions should be set to 755
.
/etc/ssh/
contains several important files.
/etc/ssh/sshd_config
-
The main configuration file for the
sshd
daemon. Its options include:AllowUsers
- Restricts logins to the SSH server to only the users listed. Specify a list of users separated by spaces.
DenyUsers
- Prevents the users listed from logging in through the SSH server. Specify a list of users separated by spaces.
HostKey
- Specifies which private host key file should be used by SSH.
ListenAddress
- If the host where
sshd
is running has multiple IP addresses assigned, you can restrictsshd
to only listening on specific addresses using this parameter. The syntax isex_listen_address ex_ip_address:ex_port
. PermitRootLogin
- Specifies whether you can authenticate through the SSH server as the root user.
Port
- Specifies the port on which
sshd
will listen for SSH requests. Protocol
- Specifies which version of SSH to use. Specify one of the following (
1
,2
,2,1
).
/etc/ssh/ssh_config
-
The main configuration file for the
ssh
client. Its options include:Port
- Specifies the port number to connect to on the SSH server system to initiate an SSH request.
Protocol
- Specifies which version of SSH to use. Specify one of the following (
1
,2
,2,1
). StrictHostKeyChecking
- If set to a value of
yes
, the client can only establish connections to SSH servers whose public key has already been added to either the/etc/ssh/ssh_known_hosts
or${HOME}/.ssh/known_hosts
file. User
- Specifies the user to log in to the SSH server as.
The precedence for SSH client configuration settings is as follows:
- Any command-line options included with the
ssh
command at the shell prompt. - Settings in the
${HOME}/.ssh/config
file. - Settings in the
/etc/ssh/ssh_config
file.
/etc/ssh/ssh_known_hosts
- This file is used to check the public key of a remote server you are attempting to connect to via SSH (i.e., it is a list of remote SSH server public keys).
/etc/ssh/ssh_host_ex_key
- The private part of the host's key structure, where
ex_key
represents a specific cryptographic method that clients can use to check for the server's authenticity (e.g.,rsa
,ecdsa
). /etc/ssh/ssh_host_ex_key.pub
- The public part of the host's key structure, where
ex_key
represents a specific cryptographic method that clients can use to check for the server's authenticity (e.g.,rsa
,ecdsa
). Its permissions should be set to644
.
User-Specific SSH Configuration
The user-specific SSH configuration directory is ${HOME}/.ssh/
. It contains several important files.
${HOME}/.ssh/config
- The user configuration file for the
ssh
client. ${HOME}/.ssh/authorized_keys
- Used to store the public keys for remote clients attempting to connect via SSH to a SSH server (i.e., this file is a list of remote SSH client public keys). These keys are matched with the keys presented by an
ssh
orscp
client upon login request. ${HOME}/.ssh/known_hosts
- Used to check the public key of a remote server you are attempting to connect to via SSH (i.e., this file is a list of remote SSH server public keys).
${HOME}/.ssh/ex_key
- The private part of the host's key structure, where
ex_key
represents a specific cryptographic method that clients can use to check for the server's authenticity (e.g.,rsa
,ecdsa
). ${HOME}/.ssh/ex_key.pub
- The public part of the host's key structure, where
ex_key
represents a specific cryptographic method that clients can use to check for the server's authenticity (e.g.,rsa
,ecdsa
). Its permissions should be set to644
.
Logging Into a Host
To log into a remote host using SSH, invoke the ssh
command:
ssh ex_host
ex_host
can be either a hostname or an IP address.
ssh
assumes that your username on the remote host is the same as the local username. If this is not the case, specify the remote user name:
ssh ex_username@ex_host
If /etc/nologin
is present, no user can log in to the system except for the root user. Non-root users will see the contents of this file (or /etc/nologin.txt
).
The SSH Connection
The following steps take place to establish a SSH connection:
-
Client and server send each other information about their host keys and supported cryptographic schemes.
The client negotiates a shared secret with the server, which then serves as the symmetric key to encrypt the connection. Simultaneously, the client checks the server's authenticity and breaks the connection if there is a discrepancy.
The details of this process are outlined in RFC4253.
-
The server checks the client's authenticity using one of several methods. The password is already sent over the encrypted connection and, unlike other protocols like FTP or TELNET, cannot be sniffed by people who listen in.
The first step is important. The following example shows what happens if you contact the remote host for the first time:
$ ssh io.example.com
The authenticity of host 'io.example.com (192.168.33.2)' can't be established.
RSA key fingerprint is 81:24:bf:3b:29:b8:f9:f3:46:57:18:1b:e8:40:5a:09.
Are you sure you want to continue connecting (yes/no)?
The host io.example.com
is still unknown here and ssh
asks you to verify its host key. If you skip this verification step, you lose the guarantee that no one is listening in to your connection.
After having established a connection using ssh
, you can use the remote host as if you were in front of it. You can close the connection using the exit
command or Control+d.
Unless you specify otherwise, during interactive ssh
sessions, the tilde (~
) is considered a special escape character if it occurs immediately after a newline character. This lets you control ssh
during an ongoing session.
In particular, the ~.
sequence will close the connection, which may be useful if a program has become stuck at the remote end. You can do other interesting things with escape characters. Run man 1 ssh
for more information.
ssh
does not restrict you to interactive sessions, but lets you execute single commands on a remote host:
$ ssh io.example.com hostname
io.example.com
Keep in mind, the shell on your computer will try to process the command line in order to replace shell wildcard patterns before it is transmitted to the remote host. Use backslashes or quotes to disable filename expansion if you are in doubt.
Verifying Remote Host Authenticity
Here, there is a danger that someone will intercept your connection request and pretend that they are a remote host that you are trying to connect to, like io.example.com
. They can surreptitiously establish their own connection to io.example.com
and pass everything along that you send to them.
Conversely, they can forward io.example.com
's answers back to you. You will not see a difference, and the attacker can read everything that you transmit, i.e., a person-in-the-middle (PITM) attack.
To check for this type of attack, you need to contact the remote system's administrator (via an out-of-band connection method, e.g., a telephone call) and ask them to read their public key's fingerprint. This can be displayed using ssh-keygen -l -f ex_ssh_pub_key_file
and must be identical to the key fingerprint
from the SSH login dialogue.
SSH Key Pairs
The SSH key pairs of a host can be found in the ssh_host_ex_key
and ssh_host_ex_key.pub
files within the /etc/ssh/
and ${HOME}/.ssh/
directories. ex_key
represents a specific cryptographic method that clients can use to check the server's authenticity.
Possible values of ex_key
include:
dsa
- The DSA algorithm. This only allows
1024
-bit keys and should be avoided because it is susceptible to weaknesses in random number generation. ecdsa
- The DSA algorithm based on elliptic curves. This lets you pick between
256
,384
, and521
bits. Elliptic curves do not need as many bits, so the lower numbers are not problematic. ed25519
- A fast and secure method invented by Daniel J. Bernstein. Within the SSH context, this is still fairly new.
rsa
- The RSA algorithm. This is secure, as long as you use keys that are longer than
2048
bits (4096
bits or higher is preferable).
An SSH key pair is a set of two matching keys, one private and one public. The public key may be told to everyone as long as the private key stays confidential. Whatever is encrypted using the public key can only be decrypted using the private key from the same pair, and vice versa (i.e., asymmetric cryptography).
Verifying Remote Server Authenticity
When connecting to a remote server via SSH and you have ensured that the remote host's public key is authentic, ssh
will store the remote server's public key in the ${HOME}/.ssh/known_hosts
file once you have agreed to accept the remote server's fingerprint. The ${HOME}/.ssh/known_hosts
file is used as a base for comparison during future connection requests.
If you ever see a WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!
message when trying to establish a ssh
connection, you may be the subject of a PITM attack. The public key that the server presents does not match the one stored for the server in the ${HOME}/.ssh/known_hosts
file. You should contact the remote host's administrator to find out what is going on (i.e., perhaps the host key needed to be changed for valid reasons).
How ssh
behaves in regard to evaluating remote hosts' keys can be configured in the ${HOME}/.ssh/config
(or the /etc/ssh/ssh_config
file for system-wide changes).
StrictHostKeyChecking ask
- The default setting.
StrictHostKeyChecking no
- Always accept everything.
StrictHostKeyChecking yes
- Never accept anything new.
When StrictHostKeyChecking yes
is set, you can only establish connections to hosts that are already in your known_hosts
file. All others will be refused.
Verifying Remote Client Authenticity
Normally, the SSH server will authenticate you as a user by means of a password that is assigned to your account on the server (usually in /etc/passwd
or /etc/shadow
). Since the password is queried only after the encrypted connection has already been established, this is, in principle, safe from unwanted listeners.
However, your password itself is stored on the server. Even though it is encrypted, the password file could be compromised. It would be better if nothing secret about you would be stored on the remote server at all.
You can achieve this by using public-key client authentication instead of the password-based client authentication. In short, you create a key pair for your SSH client consisting of a public and private key, and deposit the public key on the SSH server.
The public key does not need to be specially protected. You will need to keep the private key, which should never leave your computer (you can also put your private key on a USB stick or specialized hardware token).
Public Key Client Authentication
If you configure the SSH server to use public key authentication, the SSH client tells the SSH server which public key should be used for authentication when the SSH session is initially established. Then, the SSH server checks to see if it has that client’s public key (i.e., is the public key present in the authorized_keys
file for the associated user). If it does, it generates a random number and encrypts it with that public key.
It then sends the encrypted number to the client, which decrypts it using the private key associated with the public key. The client then calculates a checksum of the number it received from the server.
It sends the checksum to the SSH server, which then calculates its own checksum of the number it originally sent. If the two checksums match, then the user is automatically logged in.
All of the above takes place across the encrypted connection and is secure from unwanted listeners that want to manipulate your data.
To use public-key client authentication, you first need to generate a key pair. This is done using the ssh-keygen
command:
ssh-keygen -t rsa -b 4096
The -t ex_key_type
option specifies the type of key to create. Accepted values are:
dsa
ecdsa
ed25519
rsa
The -b ex_bits
option specifies the number of bits in the key to create.
First, the command asks where you want the key pair to be stored. The default location (i.e., ${HOME}/.ssh/
) is reasonable. Next, ssh-keygen
asks for a passphrase. This is used to encrypt the private key in order to prevent someone who happens to find your private key from impersonating you to a SSH server.
You must use keys without a passphrase for non-interactive SSH connections, e.g., for shell scripts and cron
jobs. In this case, you just press Enter when you are asked for the passphrase.
It is possible to connect a public key on the server with a particular command. Then, client connections using this public key will not launch a shell session. Instead, the command in question will be directly started. This can significantly mitigate the security risk with unencrypted private keys for the use of scripts.
The result of ssh-keygen
are the two files id_ex_key
and id_ex_key.pub
in the ${HOME}/.ssh/
directory (the exact key file names will depend on the type of key that you create). The former contains the private key and the latter the public key.
When you first generate a key pair, ssh-keygen
also shows you the fingerprint of the public key and a randomart image. The latter is a graphical representation of the public key, i.e., a kind of graphical fingerprint. Theoretically, this should enable you to tell at a glance whether a public key has changed or not.
The next step is to deposit the public key (i.e., the content of the id_ex_key.pub
file) in the ${HOME}/.ssh/authorized_keys
file for your user account on the remote host. This is most easily done using the ssh-copy-id
command:
ssh-copy-id ex_username@ex_remote_host
If you set the PasswordAuthentication
entry in the /etc/ssh/sshd_config
file on the remote server to no
and PubkeyAuthentication
to yes
, then users can only authenticate via the public key method. Essentially, this is a good idea since attackers enjoy running automatic programs that try obvious passwords on SSH servers.
ssh-agent
If you are using a passphrase for your private SSH key, public-key authentication is not more convenient than password authentication, but more secure. If you want to log into the same host as the same user several times in a row, constantly re-entering your private SSH key's passphrase can be a nuisance. The ssh-agent
was developed to help with this.
The ssh-agent
program remembers your private SSH key's passphrase and passes it to SSH client programs, as needed. For example, the program is started using ssh-agent bash
. This opens a new bash
shell in which you must add the private SSH key passphrase using ssh-add
:
$ ssh-add
Enter passphrase for /home/amnesia/.ssh/id_rsa: foobar
Identity added: /home/amnesia/.ssh/id_rsa (/home/amnesia/.ssh/id_rsa)
Every instance of ssh
, scp
, or sftp
started from the new shell gets the passphrase from the SSH agent. The agent forgets the passphrase once you leave the shell using exit
or instruct it to using ssh-add -D
to forget all stored identities (with Debian, the login shell/GUI may be started with the ssh-agent
active right away, so you can ssh-add
your passphrase at the very beginning of your session).
ssh-agent
increases convenience to the detriment of security. If you leave your computer unattended (or if you lose your suspended laptop), an unauthorized person might be able to use SSH programs without being asked for a passphrase. The same applies to programs that get access to your session.
Secure Copy (scp)
Using scp
, you can copy files between two hosts via an SSH connection. scp
's syntax is based on the cp
command. Files and directories can be specified with either absolute or relative paths, and ex_host
can be either a hostname or an IP address.
The following command copies remote files to a local directory:
scp ex_host:ex_source_file... ex_destination_directory
This command copies local files to a remote host:
scp ex_source_file... ex_host:ex_destination_directory
Directories can be recursively copied via scp
's -r
option. This example recursively downloads a remote directory to a local directory:
scp -r ex_host:ex_source_directory ex_destination_directory
It is possible to copy files between two remote hosts, as well. This example copies files from one remote host to another remote host:
scp \
ex_username@ex_host_1:ex_file... \
ex_username@ex_host_2:ex_destination_directory
Secure File Transfer Protocol (SFTP)
The sftp
command is loosely inspired by common FTP clients, but needs an SSH connection. Otherwise, it has nothing to do with FTP. In particular, you cannot use it to communicate with an FTP server.
sftp ex_username@ex_host
ex_host
can be either a hostname or an IP address.
After having established a connection using a command like sftp ex_username@ex_host
, you can use commands like get
or put
to transfer files between your local host and the remote host, inspect the contents of a directory on the remote host using ls
, and change into different directories on the remote server by means of cd
.
At the beginning of a session, you will be placed in your home directory on the remote computer. To end a session, enter quit
.
SSH Port Forwarding (Tunneling)
SSH can be used to encrypt clear-text traffic by tunneling it through a SSH connection. When client software for the tunneled protocol (e.g., an e-mail client using POP3) establishes a connection with the local SSH client, the traffic is encrypted using SSH and tunneled through to the SSH server.
On the SSH server's end, the traffic is decrypted and forwarded to the appropriate target service (e.g., the POP3 daemon). This is desirable because the information is encrypted before being transmitted, even though the original protocol (POP3) does not support encryption.
To utilize SSH port forwarding, ensure that AllowTcpForwarding yes
is set in the /etc/ssh/sshd_config
file.
To create a local SSH tunnel from a local high port to the port that you want to tunnel, you can use the following command (you may need to enter the remote user's password when prompted):
ssh -f -N -L \
ex_local_port_number:ex_host:ex_port_number_to_tunnel ex_username@ex_host
The -f
option tells ssh
to go into the background just before command execution and the -N
option prevents the execution of remote commands. Together, these options are useful for SSH port forwarding.
The -L
option specifies three things:
- The local port to be used for the client end of the tunnel (e.g.,
59823
). If you want to use a port number less than1024
, you will need to switch to the root user, as these are privileged ports. - The hostname or IP address of the remote server running the service that we want to tunnel (e.g., POP3).
- The port number on the remote server that will be used for the server end of the tunnel (i.e., the port number to tunnel, like port
110
for POP3).
The final argument in the above command, ex_username@ex_host
, is the remote SSH user and host.
Next, configure the local client program to receive communications via the port that you configured for the client end of the SSH tunnel (i.e., port 59823
). You can test the tunnel that you created using the netcat
command from the client end of the tunnel. The syntax is netcat localhost ex_client_tunnel_port
.
For example:
netcat localhost 59823
Afterwards, you should see a connection established with the remote system where the tunneled service daemon is running.
SSH can forward and tunnel nearly every other TCP-based protocol by using the -R
and -L
options. The following command tunnels connections to the local TCP port 10110
first via an SSH connection to the computer io.example.com
. From there, it continues (unencrypted) to the TCP port 110
(POP3) on the mail.example.com
host:
ssh -L 10110:mail.example.com:110 amnesia@io.example.com
There are benefits to this approach:
- Imagine that your firewall blocks POP3, but allows SSH traffic. By means of the port redirection, you can enter the internal network via SSH and then connect from the
io.example.com
host to the mail server on the internal network. In your mail program, you need to specifylocalhost
and the local TCP port10110
as the POP3 server.- Theoretically, You could forward the local TCP port
110
, but you need to be root to do it.
- Theoretically, You could forward the local TCP port
- The name of the forwarding destination host (i.e.,
mail.example.com
) is resolved from the perspective of the SSH server (io.example.com
). This means that a redirection of the formssh -L 10110:localhost:110 amnesia@io.example.com
connects you to port110
onio.example.com
, rather than your own computer. -
A port forwarding like
-L 10110:mail.example.com:110
opens port10110
on all IP addresses on your computer. This opens the redirection, in principle, to all other hosts that can reach this port over the network.To prevent this, you can use the fact that
ssh
allows you to specify a local address for the redirected port. With-L localhost:10110:mail.example.com:110
, the redirection only applies to the local interface.
If you invoke ssh
as shown in the ssh -L 10110:mail.example.com:110 amnesia@io.example.com
command, you get an interactive session on top of the port forwarding. If you do not need this (e.g., because the forwarding takes place within a cron
job), you can specify the previously mentioned -N
option, which restricts ssh
to do the port forwarding and not establish an interactive session.
Another technique for automatically forwarding services uses a ssh
invocation like:
$ ssh -f -L 10110:mail.example.com:110 amnesia sleep 10
$ getmail_fetch -p10110 localhost amnesiamail Mail123 Maildir/
The -f
option causes the ssh
process to immediately go to the background before the sleep 10
command is executed. This means that a command that you immediately execute after the ssh
command (here, getmail_fetch
, which retrieves email via POP3) has 10
seconds to establish a connection to the local port 10110
. The ssh
process exists either after 10
seconds or else when the last connection via the local port 10110
is torn down, whichever occurs later.
Port forwarding also works the other way around. For example, ssh -R 10631:localhost:631 amnesia@io.example.com
opens the TCP port 10631
on the SSH server, and connections that programs there make with that port are redirected across the SSH connection to your local host.
Your local host then takes care of redirecting the decrypted data to the destination, here port 631
on your local host. This type of port forwarding is considerably less important than the forwarding using -L
.
Usually, the -R
port forwarding binds the remote port to the localhost
interface on the SSH server. In principle, you can pick another interface, but whether that works or not depends on the configuration of the SSH server.
You can add port forwarding after the fact using the ~C
key combination, which gives you a command line:
$ ~C
ssh> -L 10025:localhost:25
Forwarding port
On the command line, you can add -L
and -R
options, as if you had typed them directly on the ssh
command line. Using -KR
, followed by the port number, you can also cancel a -R
port forwarding.
With the ~#
command, you can check the currently active connections:
$ ~#
The following connections are open:
#2 client-session (t4 r0 i0/0 o0/0 fd 6/7 cfd -1)
#3 direct-tcpip: listening port 10025 for localhost port 25,
connect from 127.0.0.1 port 57250
(t4 r1 i0/0 o0/0 fd 9/9 cfd -1)
X server traffic can also be tunneled to remote X clients using an SSH connection (i.e., you can execute graphical programs on a remote host, where graphics output and keyboard/mouse input take place on your local computer).
To configure a remote X client without encryption, you can use the following procedure:
- On the remote X client, enter
xhost +ex_x_server_hostname
. This tells the client to accept connections from the X server. - On the X server, enter
export DISPLAY=ex_x_client_hostname:0.0
. This tells the X server to display its output on the remote X client. - From the X client, use the
ssh
client to access the shell prompt on the X server and then run the graphical application that you want displayed on the X client.
To use SSH to tunnel the X server traffic between the X server and the X client:
-
Use the
-X
option with thessh
client program (e.g.,ssh -X ex_username@ex_host
). When logging in using-X
, theDISPLAY
variable is set up to point to a proxy X server provided bysshd
. This directs X clients started on the remote host to this server.Everything a remote X client sends to the proxy X server is sent to the (real) X server on the SSH client. All the X11 traffic is encrypted so that eavesdroppers cannot listen in (i.e., it is tunneled).
-
Set the
X11Forwarding
option toyes
in the/etc/ssh/sshd_config
file on the X server system.
You can also globally enable X11 forwarding in order to avoid having to type the -X
option. To do so, add ForwardX11 yes
to your ${HOME}/.ssh/config
SSH client configuration file (or the /etc/ssh/ssh_config
SSH client configuration file for a system-wide default).
X11 forwarding is preferable to the standard X packet redirection (using DISPLAY
) not only because of its increased security, but because it is more convenient. You pay for this with some extra effort for encryption (which, on modern hardware, is negligible).
X11 forwarding is not without security risks. Users that can circumvent file access rights on the remote host (e.g., because they are root) may access your local X11 display. For this reason, you should probably avoid globally enabling X11 forwarding. The same risk exists with conventional X11 redirection using DISPLAY
.
More information on ssh
configuration can be found by running man 5 sshd_config
.
SSH Commands
ssh-keygen -t ex_key_type -b ex_bits
- Generate authentication keys for
ssh
. - The
-t
option specifies the type of key and the-b
option specifies the number of bits in the key to create (e.g.,ssh-keygen -t rsa -b 4096
). ssh-keygen -l -f ex_public_key
- Show fingerprint of specified public key file.
- The
-l
option tellsssh-keygen
to display a public key file fingerprint and the-f
option is used to specify the filename of the public key file. - Add the
-v
option to display a visual ASCII art representation of the key along with the fingerprint (e.g.,ssh-keygen -l -f "${HOME}/.ssh/id_rsa.pub" -v
). ssh-copy-id ex_host
- Use locally available keys to authorize logins on a remote machine, i.e., upload your user's public keys to a remote server (this command assumes that you already have access to
ex_host
).ex_host
can be either a hostname or an IP address. ssh-copy-id
assembles a list of one or more fingerprints and tries to log in with each key to see if any of them are already installed. Then, it assembles a list of those that failed to log in and, usingssh
, enables logins with those keys on the remote server. By default, it adds the keys by appending them to the remote user's${HOME}/.ssh/authorized_keys
file.- The alternative
ssh-copy-id ex_username@ex_host
form can be used to specify a specific user. - The
-i ex_identity_file
option can be used to tellssh-copy-id
to only use the key(s) contained inex_identity_file
. ssh ex_destination
- Connect and log into
ex_destination
, which may be specified asex_host
,ex_username@ex_host
, or a URI of the formssh://[user@]hostname[:port]
, where[user@]
and[:port]
are optional. - Add the
-p ex_port
option tossh ex_destination
to specify the port to connect to on the remote host (ssh -p ex_port ex_destination
). - Add the
-i ex_identity_file
option tossh ex_destination
to select the file from which the identity (i.e., private key) for public key authentication is read (ssh -i ex_identity_file ex_destination
). - Append
ex_command
tossh ex_destination
to specify a command to execute on the remote host, instead of being provided with a login shell (ssh ex_destination ex_command
). - To log out of a SSH session, use the
exit
command or Control+d. ssh-agent "${SHELL}"
- Invoke the ssh-agent as a wrapper to your shell. This command puts you in a shell that is spawned by
ssh-agent
. - The
ssh-agent
resides in memory and places a security wrapper around your shell session, answering any SSH-related security requests for you. After entering a private SSH key's passphrase once,ssh-agent
will remember it and automatically apply it for you, when necessary. ssh-add
- Add your user's private SSH key to
ssh-agent
. When prompted, enter the key file’s passphrase. Once done,ssh-agent
stores the passphrase in memory. Then, it listens for SSH requests and automatically provides the key passphrase for you, when requested. - This command needs to be run after
ssh-agent "${SHELL}"
. It tries to add the standard key identity to the key manager. - A key with a different location can be added by entering
ssh-add ex_key_path
. scp ex_source... ex_target
- Copy objects between network hosts.
ex_source
andex_target
can be specified as a local path, a remote host with optional path in the form[user@]host:[path]
(e.g.,scp ex_file... ex_username@ex_host:ex_directory
orscp ex_username@ex_host:ex_file... ex_directory
), or a URI in the formscp://[user@]host[:port][/path]
.- Add the
-r
option to copy directories recursively. - Add the
-P ex_port
option to specify the port to connect to on the remote host. - Add the
-i ex_identity_file
option to select the file from which the identity (i.e., private key) for public key authentication is read. - Make sure that all used options come before the hosts in question in your
scp
commands.
Documentation
For more information on SSH, run the following commands:
man 8 sshd
man 1 ssh
man 5 ssh_config
man 1 ssh-keygen
man 1 ssh-add
man 1 ssh-agent
man 1 scp
man 1 sftp
These manual pages can also be viewed online.