Adding file encryption to file transfers: an imperfect approach

In some niche automation applications you might find yourself transferring files over TLS but still have a desire for a further layer of encryption of the file being transferred. Not so much as a strong confidentiality and integrity control, but for greater assurance. Not using PKC/certificates is also a prerequisite.

On Linux, one solution is GPG. Assuming we have one file on the sending system, the command required to automate the encryption of the file with a known passphrase would be:

$ gpg --yes --batch --passphrase=[secret] -c ${srcfile}

The output file is “${srcfile}.gpg”.

On the receiving system, the corresponding decrypt command would be:

$ gpg --yes --batch --passphrase=[secret] -d ${encfile} >

By default, GPG will use the AES128 cipher in version 2.1 and later, and CAST in earlier versions. You might seek to use a longer key length cipher, such as AES256. This is achieved by adding the following switch to each command:

… --cipher-algo AES256 …

Due to the number of rounds that AES will require for greater key sizes, AES 256 has a 40%+ performance penalty over AES 128, so you might find AES192 fits your requirements better.

Available ciphers depends on your implementation, and can be viewed using:

$ gpg --version

Some common ones under GPG include IDEA, 3DES, CAST5, BLOWFISH, AES, AES192, AES256, TWOFISH, CAMELLIA128, CAMELLIA192, CAMELLIA256. For large file encryption, it’s always worthwhile checking cipher performance at the outset. You might also glean some useful information from the OpenSSL speed test for your particular CPU:

$ openssl speed

The secret/passphrase is a symmetric key and ought to be as secure as possible, and given the application is M2M then transferring files using a high-strength key is a given. OpenSSL provides a suitable command to generate from a random source, for example, a 45 character base64 password:

# openssl rand -base64 45

There are some weighty drawbacks with this method. By default, passphrases passed in a command line on Linux will be viewable by other users in the system using “ps -ef” or by exploring the proc filesystem. They do not need superuser privileges to do that.

Whether data passed in this way will be suitable will boil down to the security governance of the M2M hosts sending and receiving data, and more generally the risk assessment. If they are not shared systems, it may be an acceptable with some minor additional controls (key change procedure, patch management plan, etc).

As the password is passed on the command line, this would be accessible to other users in the event either system is shared with untrusted users. Any test commands will also be deposited in the bash command line history and the passphrase will inevitably be referenced from, or stored in, a script. These are not unique to this approach: using asymmetric crypto will necessitate a private key that is equally as sensitive

A workaround to parameter visibility is to use standard input (STDIN) to input the passphrase into GPG as follows:

$ echo “[secret]” | gpg --yes --batch –passphrase-fd 0 -d ${encfile}
> ${decfile}

Even still, we are left with a script containing an embedded key. It will also not help if other users can read the script containing the passphrase, so it should be suitably secured:

$ chmod u+r+w+X,g-r-w-X,o-r-w-X [scriptname]

Finally, also ensure the locations used to write files as input and output to the process are also secured in the same way.

Passing the passphrase on the command line is not ideal and using a public key based solution and certificates with GPG is much more preferable. That brings its own issues, chief among them being the governance wrap needed around key and certificate management (particularly in enterprise environments).

Moreover, key expiry, particularly in M2M solutions, would be a significant risk to availability (think Siemens and O2).

When I get a few minutes I’ll write up the PKC-based equivalent for this post, stay tuned.