Flat-file encryption with OpenSSL and GPG

by Charles Fisher


The "Pretty Good Privacy" (PGP) application has long been known as a primary tool for file encryption, commonly focused on email. It has management tools for exchanging credentials with peers and creating secure communication channels over untrusted networks. GNU Privacy Guard (GPG) has carried on this legacy with a free and open implementation included in most major Linux distributions. PGP/GPG has proven highly resistant to cryptographic attack, and is a preeminent tool for secure communications.

OpenSSL is more known for network security, but it also has tools useful for most aspects of encrypting flat files. While using OpenSSL requires more knowledge of specific algorithms and methods, it can be more flexible in a number of scenarios than other approaches. Interestingly, OpenSSH keys can be transparently used for flat file encryption with OpenSSL, allowing user and/or host SSH keys to pervade any number of unrelated services.

OpenSSL is also useful for illustrating the sequence of encryption techniques that create secure channels. This knowledge is applicable in many other situations, so the material is worth study even if there is no immediate need for the tools.

OpenSSL Flat-File Processing

Many common programs in UNIX have implementations within the OpenSSL command line utility. These include digest/checksum tools (md5sum, sha1sum, sha256sum), "ASCII-Armor" tools (base64/uuencode/uudecode), (safe) random number generation, and MIME functions in addition to a suite of cipher and key management utilities. Since OpenSSL is often found on non-UNIX platforms, these utilities can provide a familiar interface on unfamiliar systems for UNIX administrators.

We will begin with a complete script for flat-file encryption with OpenSSL, using asymmetric exchange of a session key, SHA-256 digest checksums, and the use of a symmetric cipher. This entire exchange, both to encode and decode, is presented in the following text for the Korn shell (GNU Bash may also be used with no required changes):


set -euo pipefail
IFS=$'\n\t' #http://redsymbol.net/articles/unofficial-bash-strict-mode/

# openssl genrsa -aes256 -out ~/.prv.key 2868         # Make private key
# openssl rsa -in ~/.prv.key -pubout -out ~/.pub.key  # Make public key

PVK=~/.prv.key; PBK=~/.pub.key
SKEY=$(mktemp -t crypter-session_key-XXXXXX)          # Symmetric key

case $(basename "${0}") in

encrypter) #####sender needs only public key - not .pas or .prv.key######
 openssl rand -base64 48 -out "${SKEY}"               # Generate sesskey
 openssl rsautl -encrypt -pubin -inkey "${PBK}" -in "${SKEY}" |
  openssl base64;
 echo __:
 for F                                                # Generate digest
 do echo $(openssl dgst -sha256 "${F}" | sed 's/^[^ ]*[ ]//') "${F}"
 done | openssl enc -aes-128-cbc -salt -a -e -pass "file:${SKEY}"
 echo __:
 for F                                                # Encrypt files
 do openssl enc -aes-128-cbc -salt -a -e -pass "file:${SKEY}" -in "${F}"
    echo __:
 done ;;

decrypter) #####receiver#################################################
 TMP=$(mktemp -t crypter-tmp-XXXXXX); PW=${HOME}/.pas; unset IFS
 DGST=$(mktemp -t crypter-dgst-XXXXXX); #cd ${HOME}/dest #unpack dest
 while read Z
 do if [[ ${Z%%:*} == '__' ]]
    then if [[ -s "${SKEY}" ]]
         then if [[ -s "${DGST}" ]]
              then openssl enc -aes-128-cbc -d -salt -a -in "${TMP}" \
                    -pass "file:${SKEY}" -out "${NAME[I]}"
                   ((I+=1))                           # Decrypt files
              else openssl enc -aes-128-cbc -d -salt -a -in "${TMP}" \
                    -pass "file:${SKEY}" -out "${DGST}"
                   date +%Y/%m/%d:%H:%M:%S
                   while read hash file
                   do echo "${hash} ${file}"
                      NAME[I]=$(basename "${file}")   # Unpack only @dest
                   done < "${DGST}"
         else openssl base64 -d -in "${TMP}" |        # Extract sesskey
               openssl rsautl -decrypt -inkey "${PVK}" \
                -passin "file:${PW}" -out "${SKEY}"

              #Older OpenSSL: decrypt PVK; c/sha256/sha1/; no strict
              #openssl rsa -in "${PVK}" -passin "file:${PW}" -out "$DGST"
              #openssl base64 -d -in "${TMP}" |	      # Extract sesskey
	      # openssl rsautl -decrypt -inkey "${DGST}" -out "${SKEY}"
              #> "${DGST}"
         > "${TMP}"                                   # Erase tempfile
    else echo "${Z}" >> ${TMP}
 while [[ ${I} -lt ${#NAME[*]} ]]                     # Verify digest
 do F=$(openssl dgst -sha256 "${NAME[I]}" | sed 's/^[^ ]*[ ]//')
    if [[ "${F}" = "${HASH[I]}" ]]
    then echo "${NAME[I]}: ok"; else echo "${NAME[I]}: **SHA CORRUPT**"
 rm "${TMP}" "${DGST}" ;;

rm "${SKEY}"

We will specifically cover everything above to the end of the "encrypter" case block, as this succinctly addresses major cryptographic components of most encryption tools - i.e. SSH, TLS, PGP, etc.

First we include a well-known strict mode for Korn/Bash published by Aaron Maxwell which can prevent coding errors, as documented at the URL near the top of the script.

Next, we generate an RSA private key. RSA, as an "asymmetric cipher," uses pairs of keys for communication, and was developed by Ron Rivest, Adi Shamir, and Leonard Adleman in 1977. Other asymmetric ciphers in common use are Diffie-Hellman key exchange and Elliptic Curve, but OpenSSL's support for RSA is more thorough, complete and widespread (a bug listed in OpenSSL's dhparam manual page indicates "There should be a way to generate and manipulate DH keys."). With an asymmetric cipher, content encrypted by one key can only be read in cleartext by the other. We can use such keypairs not only to communicate securely, but also to prove authenticity. Below is an example of the generation of an RSA private key of a non-standard size of 2868 bits:

$ openssl genrsa -aes256 -out ~/.prv.key 2868
Generating RSA private key, 2868 bit long modulus
e is 65537 (0x10001)
Enter pass phrase for /home/ol7_user/.prv.key:
Verifying - Enter pass phrase for /home/ol7_user/.prv.key:

$ chmod 400 .prv.key

$ cat .prv.key
Proc-Type: 4,ENCRYPTED
DEK-Info: AES-256-CBC,16846D1D37C82C834E65B518C456DE2F


We have chosen this non-standard key size based upon recommendations from the U.S. National Institute of Standards (NIST). NIST uses a "general number field sieve" on page 92 of their implementation guidance document to determine minimum RSA key size. We can implement this formula with the GNU bc utlitity (part of GNU Coreutils):

$ cat keysize-NIST.bc 
#!/usr/bin/bc -l
l = read()
scale = 14; a = 1/3; b = 2/3; t = l * l(2); m = l(t) # a^b == e(l(a) * b)
n = e( l(m) * b ); o = e( l(t) * a ); p = (1.923 * o * n - 4.69) / l(2)
print "Strength: ", p, "\n"

$ echo 2868 | ./keysize-NIST.bc 
Strength: 128.01675571278223
$ echo 7295 | ./keysize-NIST.bc 
Strength: 192.00346260354399
$ echo 14446 | ./keysize-NIST.bc 
Strength: 256.00032964845911

$ echo 2048 | ./keysize-NIST.bc
Strength: 110.11760837749330
$ echo 2127 | ./keysize-NIST.bc
Strength: 112.01273358822347

In general, asymmetric ciphers are slower and weaker than "symmetric ciphers" (which are defined as only using one key to both encrypt and decrypt). We will later be using a 128-bit symmetric cipher to communicate the bulk of our data, so we will use an RSA key of (strictly) comparable strength of 2868 bits. Please note that there are many who feel that RSA keysizes over 2048 bits are a waste. Still, the most forward thinkers in cryptography conjecture that there may be "...some mathematical breakthrough that affects one or more public-key algorithms. There are a lot of mathematical tricks involved in public-key cryptanalysis, and absolutely no theory that provides any limits on how powerful those tricks can be... The fix is easy: increase the key lengths." In any case, we are strictly following NIST's recommended guidelines as we generate the key.

I have listed 192 and 256 bit equivalences because our symmetric cipher is not approved for "top secret" use at 128 bits. For highly-sensitive information that must be kept secret, consider an RSA keysize of 7295 or 14446 bits as (strictly) recommended by NIST's formula. Note that an RSA keysize of 2048 bits computes to 110 bits of equivalent strength. This is below the requirement of RFC-7525 of a minimum of 112 bits of security (128 recommended) - 2127-bit RSA keys satisfy this mandate.

A corresponding public key can be generated for use with our script:

$ openssl rsa -in ~/.prv.key -pubout -out ~/.pub.key
Enter pass phrase for /home/ol7_user/.prv.key:
writing RSA key

$ cat .pub.key
-----END PUBLIC KEY-----

Interestingly, our private key is compatible with the OpenSSH Protocol 2 RSA format, and we can generate what would normally be stored as the "id_rsa.pub" file with a simple keygen command:

$ ssh-keygen -y -f ~/.prv.key 
Enter passphrase: 
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABZwqkByyctfGgfj553YGh/Yi6k4TBNh3P43lH7

An SSH server also runs with several types of host keys (which do not normally use a password), usually of 2048 bits in size. A host's private RSA key can be used with our crypter script by generating a compatible public key with this command:

# openssl rsa -in /etc/ssh/ssh_host_rsa_key -pubout
writing RSA key
-----END PUBLIC KEY-----

Since we will be using this RSA keypair for batch transfers, we will be recording the cleartext password for this key in the ~/.pas file. Because of this, the RSA key likely should not be used for SSH. OpenSSL is able to read passwords from a variety of other sources, so if you remove the ~/.pas file and supply the password from a more secure source, then the use of a single RSA key for both SSH network sessions and OpenSSL flat-file encryption becomes more of an option. Alternately, use a key without a password, and dispense with the ${PW} clauses above.

We cannot use the RSA keypair for the bulk of the encryption of a large amount of data, because RSA can only encode small amounts of information, as is detailed in the manual page:

$ man rsautl | col -b | awk '/NOTES/,/^$/'
  rsautl, because it uses the RSA algorithm directly, can only be used to
  sign or verify small pieces of data.

Echoing a string of zeroes to a text file, the maximum size of the cleartext input for RSA encryption with our 2868-bit RSA key is 348 bytes:

$ for((x=0;x<348;x+=1));do echo -n 0 >> bar;done

$ ll bar
-rw-rw-r--. 1 ol7_user ol7_user 348 Jul  7 17:49 bar

$ openssl rsautl -encrypt -pubin -inkey ~/.pub.key -in bar |
	openssl base64

$ echo -n 0 >> bar

$ ll bar
-rw-rw-r--. 1 ol7_user ol7_user 349 Jul  7 17:49 bar

$ openssl rsautl -encrypt -pubin -inkey ~/.pub.key -in bar |
	openssl base64
RSA operation error
139936549824416:error:0406D06E:rsa routines:
RSA_padding_add_PKCS1_type_2:data too large for key size:

Similar testing with a 2048-bit RSA key yeilds a maximum of 245 bytes (slightly smaller than the size of the key).

Because of this limitation, we will generate a random 64-character password with OpenSSL's random number generator, encrypt a copy of it in the output with the public key, then use it for symmetric encryption for the bulk of the data as the "session key." For our example, we will use the following password obtained from OpenSSL in this manner:

$ openssl rand -base64 48 

If we store this file as /tmp/skey, we can see the encryption take place:

$ openssl rsautl -encrypt -pubin -inkey ~/.pub.key -in /tmp/skey |
	openssl base64

Note above the call to the base64 function - the encrypted output is a binary file, and it cannot be displayed directly with the standard ASCII 7-bit character set. The base64 encoder changes binary data into a stream of printable characters suitable for transmission over 7-bit channels - email, for example. This performs the same function as uuencode, using different ASCII symbols.

If we record the output of the encryption in the /tmp/ekey file, we can decrypt it with the private key:

$ openssl base64 -d < /tmp/ekey |
	openssl rsautl -decrypt -inkey ~/.prv.key 
Enter pass phrase for .prv.key:

Note above in the decryption section that very old versions of the OpenSSL rsautl command did not allow passwords to be specified on the command line. Therefore, an unencrypted copy of the key must be created before RSA decryption of the session key can take place. That procedure is documented in the comments for legacy systems and versions.

With the session key in hand, we next compute SHA-256 digest checksums of all the input files, and record the encrypted results in the output. OpenSSL's version of the sha256sum utility differs slightly in formatting from the conventional version. Also included are SHA-1, RIPEMD-160, and MD5 checksums below. The SHA-familiy of digests were all created by the NSA, to whom we owe a great debt for their publication. The RIPEMD-160 digest was developed by researchers in Belgium, and is an open alternative to SHA with no known flaws, but it is slower than SHA-1 and was released afterwards, so it is not used as often. MD5 digests should not be used beyond basic media error detection as they are vulnerable to tampering.

$ sha256sum /etc/resolv.conf 
04655aaa80ee78632d616c1...4bd61c70b7550eacd5d10e8961a70  /etc/resolv.conf

$ openssl dgst -sha256 /etc/resolv.conf 
SHA256(/etc/resolv.conf)= 04655aaa80ee78632d6...1c70b7550eacd5d10e8961a70

$ openssl dgst -sha1 /etc/resolv.conf
SHA1(/etc/resolv.conf)= adffc1b0f9620b6709e299299d2ea98414adca2c
$ openssl dgst -ripemd160 /etc/resolv.conf 
RIPEMD160(/etc/resolv.conf)= 9929f6385e3260e52ba8ef58a0000ad1261f4f31
$ openssl dgst -md5 /etc/resolv.conf
MD5(/etc/resolv.conf)= 6ce7764fb66a70f6414e9f56a7e1d15b

The script adjusts the format produced by OpenSSL to more closely mimic the standard utility, then uses the AES128-CBC symmetric cipher to code the digest for all the input files after printing a delimiter (__:). Very old versions of the OpenSSL utility might lack SHA-256 - notes in the script detail downgrading to the weaker SHA-1 when using legacy systems (MD5 should never be used). The "man dgst" command will give full details on OpenSSL's digest options if the manual pages are available.

Finally, the script enters the main encryption loop where each file is processed with AES128-CBC, encoded with base64, separated by delimeters, then sent to STDOUT under the intention that the script be redirected/piped to a file or program for further processing. Information on OpenSSL's various symmetric ciphers can be found with the "man enc" command when the manual pages are accessibly installed. An informative and amusing cartoon has been published online covering AES' history and theory of operation, for those who have a deeper interest in our chosen symmetric cipher. The GPG website currently advocates Camellia and Twofish in addition to AES, and Camellia can be found in OpenSSL.

OpenSSL can be called to encrypt a file to the standard output with AES like so:

openssl enc -aes-128-cbc -salt -a -e -pass file:pw.txt -in file.txt > file.aes

The encryption is undone like so:

openssl enc -aes-128-cbc -d -salt -a -pass file:pw.txt -in file.aes

Here is an example of a complete run of the script:

$ ln -s crypter.sh encrypter
$ ln -s crypter.sh decrypter
$ chmod 755 crypter.sh

$ ./encrypter /etc/resolv.conf /etc/hostname > foo

$ ./decrypter < foo
04655aaa80ee78632d616c1...4bd61c70b7550eacd5d10e8961a70 /etc/resolv.conf
4796631793e89e4d6b5b203...37a4168b139ecdaee6a4a55b03468 /etc/hostname
resolv.conf: ok
hostname: ok

To use this script, or otherwise use the OpenSSL utility for secure communication, it is only necessary to send a public key to a distant party. Assuming that the integrity of the public key is verified between the sender and receiver (i.e. via a SHA-256 sum over the phone, or another trusted channel), the sender can create a session key, then use it to encode and send arbitrary amounts of data through any untrusted yet reliable transfer medium with reasonable confidence of secrecy.

Note that the decryption block uses shell arrays, which are limited to 1024 elements in some versions (ksh88, pdksh). That will be a hard file limit in those cases.

This entire script can be worked into an email system for automated transfers. To do this on Oracle Linux 7 with the default Postfix SMTP server, ensure that the following two lines are set in /etc/postfix/main.cf:

inet_interfaces = $myhostname, localhost
default_privs = nobody

Here we will place a copy of the SSH private RSA host key in the /etc/postfix directory, set the configuration and permissions, open firewall port 25, then generate a public key as outlined below:

cd /etc/postfix
cp /etc/ssh/ssh_host_rsa_key .prv.key
chown nobody:nobody .prv.key
chmod 400 .prv.key
chcon system_u:object_r:postfix_etc_t:s0 .prv.key
iptables -I INPUT -p tcp --dport 25 --syn -j ACCEPT
openssl rsa -in .prv.key -pubout -out .pub.key

Notice that we are using the nobody user with the system host key. If you are not comfortable with this security, note that the key file is in the ssh_keys group, and create a separate user for postfix to handle the keypair.

Next, place a copy of decrypter in /etc/postfix. The script must be modified to: 1. skip the email header, 2. remove the password clause from the host key processing, 3. set /tmp as the unpack directory, and 4. define new locations for the keypair. Below sed is used with in-place editing to accomplish this:

sed -i.old '/^ while read Z/s:^:sed '"'"'1,/^$/d'"'"' |:
	s/^[ ]*-passin "[^"]*"//
	/^ DGST=/s:#.*$:cd /tmp:
	/^PVK=/c \
PVK=/etc/postfix/.prv.key; PBK=/etc/postfix/.pub.key' decrypter

With those changes in place, we create an email alias that will trigger the decrypter:

echo 'crypter: "| /etc/postfix/decrypter >> /tmp/cryp.log 2>&1"' \
	>> /etc/aliases
chcon system_u:object_r:postfix_local_exec_t:s0 decrypter
postfix reload
systemctl restart postfix.service

Now, pipe the encrypter output to the mail client:

cd /etc
encrypter resolv.conf hostname | mail crypter@localhost

The files sent into the mail client should appear in /tmp. Move the public key to a remote server, and automatic ecrypted file transfer over SMTP is established.

It is also possible to work RSA encryption in reverse, decrypting with the public key. This is useful in establishing authenticity of data. For example, to encrypt a small amount of cleartext (bounded by RSA length limitations) with the private key:

echo 'I have control of the private key.' |
  openssl rsautl -sign -inkey ~/.prv.key -passin "file:$HOME/.pas" |
  openssl base64 > blob

The "blob" file can then be posted in a public medium (website, file server, etc.), and holders of the public key can successfully decrypt the message like so:

openssl base64 -d < blob |
	openssl rsautl -inkey ~/.pub.key -pubin

In doing so, users verify that the private key was involved in the creation of the message, lending some authenticity to the data that has been transferred. The public key is not assumed to be secret, so this establishes data authenticity, not data privacy.

Rather than arbitrary text, we can pipe in the text from a SHA-256 signature program call, and thus "sign" a larger file in a way that proves authenticity:

openssl dgst -sha256 crypter.sh |
  openssl rsautl -sign -inkey ~/.prv.key -passin "file:$HOME/.pas" |
  openssl base64 > csign

We decrypt this text in exactly the same manner as we did before, producing a SHA-256 cleartext digest that we can independently verify. However, OpenSSL can summarize in one step the signed SHA-256 checksum (note that full x.509 keys can also be manipulated to sign a digest):

openssl dgst -sha256 -sign ~/.prv.key \
	-out crypter.sha256 crypter.sh

If the two files above are placed accessibly, then holders of the public key can verify that the files have not been altered:

openssl dgst -sha256 -verify ~/.pub.key \
	-signature crypter.sha256 crypter.sh

OpenSSL should output "Verified OK" when the files are intact. The capability of using an encrypted SHA-256 digest to securely verify a file is far beyond the features of the standard sha256sum utility, and demonstrates authenticity unambiguously.

Introduction to GPG

GNU Privacy Guard has much more comprehensive tools for the management of keypairs and peer identities. This includes databases for storing the various types of keys, tools for revocation of keys, and mechanisms for establishing key reputation in a "web of trust."

Oracle Linux 7 bundles GPG 2.0.22, which uses the 128-bit CAST5 symmetric cipher by default (newer versions have switched to AES128). We will conform to the previous NIST guidelines for a 2868-bit asymmetric keypair of equal strength. The GPG documentation does warn that "moving past RSA-2048 means you lose the ability to migrate your certificate to a smartcard, or to effectively use it on some mobile devices, or to interoperate with other OpenPGP applications that don't handle large keys gracefully."

$ gpg --gen-key

gpg (GnuPG) 2.0.22; Copyright (C) 2013 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.

gpg: directory `/home/ol7_user/.gnupg' created
gpg: new configuration file `/home/ol7_user/.gnupg/gpg.conf' created
gpg: WARNING: options in `/home/ol7_user/.gnupg/gpg.conf' are not yet
	active during this run
gpg: keyring `/home/ol7_user/.gnupg/secring.gpg' created
gpg: keyring `/home/ol7_user/.gnupg/pubring.gpg' created
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? (2048) 2868
Requested keysize is 2868 bits
rounded up to 2880 bits
Please specify how long the key should be valid.
         0 = key does not expire
        = key expires in n days
      w = key expires in n weeks
      m = key expires in n months
      y = key expires in n years
Key is valid for? (0) 5y
Key expires at Sat 10 Jul 2021 08:40:19 PM CDT
Is this correct? (y/N) y

GnuPG needs to construct a user ID to identify your key.

Real name: Oracle Linux
Email address: ol7_user@localhost
Comment: Test Key
You selected this USER-ID:
    "Oracle Linux (Test Key) <ol7_user@localhost>

Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? O
You need a Passphrase to protect your secret key.

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: /home/ol7_user/.gnupg/trustdb.gpg: trustdb created
gpg: key 6F862596 marked as ultimately trusted
public and secret key created and signed.

gpg: checking the trustdb
gpg: 3 marginal(s) needed, 1 complete(s) needed, PGP trust model
gpg: depth: 0  valid:   1  signed:   0  trust: 0-, 0q, 0n, 0m, 0f, 1u
gpg: next trustdb check due at 2021-07-11
pub   2880R/6F862596 2016-07-12 [expires: 2021-07-11]
      Key fingerprint = F423 3B2C ACE1 AD0E 95C3  4769 679D 66ED 6F86 2596
uid                  Oracle Linux (Test Key) 
sub   2880R/FF79FC31 2016-07-12 [expires: 2021-07-11]

Once the (rounded-up) 2880-bit private key has been created, a command is needed to generate a public key that can be shared with others:

$ gpg --export -a 

Version: GnuPG v2.0.22 (GNU/Linux)


This key would typically be included in a signature at the end of email messages, bundled with software or documentation that requires either privacy or authenticity, or pasted in a public forum (such as a website) where similar activities might take place.

Other GPG/PGP users that desired to communicate with the originator of this key might then import it, prior to engaging in these activities:

$ gpg --import /tmp/test.pub
gpg: key F3BD3FF5:
public key "Test User (Test Key) <testuser@localhost>" imported
gpg: Total number processed: 1
gpg:               imported: 1  (RSA: 1)
$ gpg --import /tmp/ol7.pub 
gpg: key 6F862596:
public key "Oracle Linux (Test Key) <ol7_user@localhost>" imported
gpg: Total number processed: 1
gpg:               imported: 1  (RSA: 1)

There are many email packages that will use various PGP components directly, enabling integrated cryptography. Our focus is flat-file encryption, so we will confine our GPG demonstration to this specific action, and use it to encrypt the script from the last section, sending from ol7_user@localhost to testuser@localhost:

$ gpg -u ol7_user@localhost -r testuser@localhost --armor --sign --encrypt crypter.sh

You need a passphrase to unlock the secret key for
user: "Oracle Linux (Test Key) "
2880-bit RSA key, ID 6F862596, created 2016-07-12

$ mv crypter.sh.asc /tmp

$ head -5 /tmp/crypter.sh.asc
Version: GnuPG v2.0.22 (GNU/Linux)


The recipient (testuser) is then able to login and decrypt (which will go to the standard output by default):

gpg -d /tmp/crypter.sh.asc

Any activity that causes GPG to request the password to a key will spawn an "agent" which will tie future GPG sessions and supply credentials so the key password need not be entered repeatedly:

testuser 4252 0:00 gpg-agent --daemon --use-standard-socket

The holder of a gpg private key can also digitally sign fies in a manner similar to OpenSSL (but somewhat more flexible). There are three methods to add signatures: create a compressed binary file that contains a packed copy of the orignal message, add a cleartext "ASCII-armored" signature that allows the original content to be read, or write a binary signature to a separate file (requiring both a clean file and signature to validate). The first method writes a compressed binary to a new file with a .gpg extension:

gpg -s crypter.sh
gpg --sign crypter.sh

The second method will add a cleartext signature, allowing the original content to remain visible, into a new file with an .asc extension:

gpg --clearsign crypter.sh

The third will write a binary signature to a separate file with a .sig extension:

gpg -b crypter.sh
gpg --detach-sign crypter.sh

All of these methods can be verified by holders of the public key with the "gpg -v (file)" command, where (file) points at the output of GPG.

While GPG has the ability to support many types of digests and ciphers, forcing specific algorithms can cause compatibility problems with users of various distributions and versions of PGP software. It is wise to adhere to the capabilities of general versions, rather than specify algorithms directly. This discussion can be found in the "man gpg" pages.

man gpg | col -b | awk '/^INTEROPERABILITY/,/reduce/'

  GnuPG tries to be a very flexible implementation of the  OpenPGP  stan-
  dard. In particular, GnuPG implements many of the optional parts of the
  standard, such as the SHA-512 hash, and the ZLIB and BZIP2  compression
  algorithms.  It  is important to be aware that not all OpenPGP programs
  implement these optional algorithms and that by forcing their  use  via
  the  --cipher-algo,  --digest-algo,  --cert-digest-algo, or --compress-
  algo options in GnuPG, it is  possible  to  create  a  perfectly  valid
  OpenPGP message, but one that cannot be read by the intended recipient.

  There  are dozens of variations of OpenPGP programs available, and each
  supports a slightly different subset of these optional algorithms.  For
  example,  until  recently,  no  (unhacked) version of PGP supported the
  BLOWFISH cipher algorithm. A message using BLOWFISH simply could not be
  read by a PGP user. By default, GnuPG uses the standard OpenPGP prefer-
  ences system that will always do the right thing  and  create  messages
  that  are usable by all recipients, regardless of which OpenPGP program
  they use. Only override this safe default if you really know  what  you
  are doing.

  If you absolutely must override the safe default, or if the preferences
  on a given key are invalid for some reason,  you  are  far  better  off
  using  the --pgp6, --pgp7, or --pgp8 options. These options are safe as
  they do not force any particular algorithms in  violation  of  OpenPGP,
  but rather reduce the available algorithms to a "PGP-safe" list.

GPG also has the ability to be used non-interactively with the --batch and the various --passphrase options. It is likely unwise to use the same keys for both interactive and batch activity - use an email key for online communication, and a batch key for automated activities. GPG offers several options for key revocation - be ready to use them for any key that is compromised, especially automated keys.


OpenSSL flat file use might be preferable to network services like TLS (or even SSH) for several reasons:

There are a few drawbacks to using the crypter script as presented:

GPG also has a few concerns:

None of these tools are perfect, but they are the bedrock of secure communications. To ponder the scale of their influence upon commerce and trusted communication is almost beyond comprehension. These algorithms are as ubiquituous as they are generally unknown.

Hopefully, this tutorial has cast a bit more light upon them.