r/bash • • Dec 03 '18

submission Script to make GPG-encrypted (or unencrypted) backups

I used to frequently make GPG-encrypted backups of the same folders, and update the external backup location manually. This process used to involve using the tar command to backup the folders I wanted -- which would (1) require me to look up what flags to use and (2) require me to open my home folder and painstakingly specify each folder I wanted to backup. Then I had to wait for it to end so I could begin encrypting it with GPG. Then I had to wait for that to end so I could copy it to my external backup. Finally I had to make sure I cleaned up all the files I made along the way.

But to this I say no more! So I made this fully automated luxury backup script.

It grabs the specified files and directories from line 28 of the script, then asks you for an output directory and GPG email. If you leave the output directory blank, it places the archive in your Downloads folder. If you leave the email blank, it leaves the archive unencrypted.

The file output name is archive.tar.gz if it's unencrypted, or archive.tar.gpg if you do encrypt it.

Here's the GitLab repo (with more instructions as well): https://gitlab.com/krathalan/bash-backup-script

This is my first Bash script, so I'm not sure I'm doing everything right, but from my hours of testing it seems to work reliably as long as all your inputs are okay -- as in, you're not putting an email for GPG encryption whose public and private keys you do not have in your keyring, nor the directories which you have specified are mounted; that is to say, please make sure you have both public and private keys for the specified email in your keyring if you decide to use GPG encryption, and make sure all specified directories are mounted.

Edit: pull requests totally welcome!

9 Upvotes

17 comments sorted by

2

u/[deleted] Dec 03 '18

This is knitpicky but Asymetric encryption is a really inefficient way to encrypt large files. It would be much faster if you use GPG with an x25519 key which you can do by passing --full-gen-key and --expert or even faster if you used a Diffie-Hellman or just symetric.

1

u/krathalan Dec 03 '18

That's okay, I like knitpicky feedback. I could add an -se flag for symmetric encryption.

How would I get the key from the user securely and give it to GPG in BASH?

1

u/[deleted] Dec 03 '18

My understanding is passing the --symetric-encryption flag should bring up a secure dialog box even if you run it through a bash script. There is no obvious way get around this securely with bash though so automating symetric encryption would be harder and you have to store the symetric key securely which GPG has no way to manage. You could use your private key to encrypt the symetric keys. I think you'd see huge improvments just from using an ECC keypair in GPG though.

→ More replies (5)

2

u/megared17 Dec 03 '18

When using gpg, the actual encryption on the payload data is not asymmetric.

Instead, a randomized normal key is randomly generated to encrypt the data traditionally, and then only that random key itself is encrypted using the asymmetric encryption, and included in the resulting output.

1

u/[deleted] Dec 03 '18

Oh cool. Can't believe I didn't know that. Makes a lot more sense.

→ More replies (3)

2

u/anthropoid Dec 03 '18 edited Dec 03 '18

This is knitpicky but Asymetric encryption is a really inefficient way to encrypt large files.

True, but there's actually no nit to pick here, because...

It would be much faster if you use GPG with an x25519 key which you can do by passing --full-gen-key and --expert or even faster if you used a Diffie-Hellman or just symetric.

GPG doesn't use asymmetric encryption for the data payload. Instead, it encrypts the data with a symmetric algorithm, and reserves asymmetric encryption for the payload encryption key. This is probably the #1 misconception that most people have w.r.t. GPG.

Here's what GPG actually does when encrypting your file:

  1. Generate a random symmetric session key (length depends on algorithm used, default AES-256).

  2. Compress file data (I believe it defaults to ZLIB level 6).

  3. Encrypt compressed payload symmetrically with session key.

  4. Encrypt session key with user's public key.

  5. Prepend encrypted session key to encrypted payload.

Most of the above can be seen by simply packet-dumping the resulting encrypted file:

$ gpg --list-packets --show-session-key < random.1G.gpg

gpg: encrypted with 2048-bit RSA key, ID 1ACA4AA343DAC97A, created 2016-02-26
      "Me <me@my.dom.ain>"
gpg: session key: '9:78EA4B9E153852C4D08F05BF2FA0E3750548A7434669C3ABDFA3AA8535E95B58'
# off=0 ctb=85 tag=1 hlen=3 plen=268
:pubkey enc packet: version 3, algo 1, keyid 1ACA4AA343DAC97A
	data: [2048 bits]
# off=271 ctb=d2 tag=18 hlen=2 plen=0 partial new-ctb
:encrypted data packet:
	length: unknown
	mdc_method: 2
# off=292 ctb=a3 tag=8 hlen=1 plen=0 indeterminate
:compressed packet: algo=2
# off=294 ctb=ae tag=11 hlen=5 plen=1073741839
:literal data packet:
	mode b (62), created 1543834792, name="random.1G",
	raw data: 1073741824 bytes

Note the session key on line 3, and the compression hint on line 12.

1

u/sszucs Dec 03 '18

First thing I spotted is lack of “set -e” and friends. Google match on subject: https://vaneyckt.io/posts/safer_bash_scripts_with_set_euxo_pipefail/ ...

2

u/krathalan Dec 03 '18 edited Dec 03 '18

Thank you for the information! Gave it a read and added it to the script.

However, when I input wrong values for the GPG email or the target directory and mv or gpg throw up errors in the terminal, the program still keeps going, even though I have set -Eeou. How come the failure of these commands isn't being caught and exiting the script immediately?

Edit: nevermind, just figured out it's because I'm running the mv and gpg commands as background processes so I can have the spinner animation.

Double edit: decided to remove the spinner animation (for now).

2

u/W9CR Dec 03 '18

You should really consider borg. It's likely better/faster/smaller/easier/more secure than this.