13

I know, the general advice is "keep your hands off crypto stuff". And the standard way to encrypt backup data securely would be using GnuPG. However, for a rather academic exercise, I would like to think through a protocol that would work just with OpenSSL's standard tools (i. e. dgst, enc, rsautl & Co) invoked from a POSIX shell.

The scenario includes a more or less trusted system on and from which backups are created - this could e. g. be a mail or file server. Then there's a storage which is not 100% to be trusted (e. g. a cloud storage, or a backup server not entirely under my control). So the purpose of the crypto is to protect confidentiality and integrity of the data while stored on the untrusted storage. This protection should also work in case the trusted system gets compromised - at least for data stored before the trusted system was compromised.

So here's a kind of protocol that should fulfill the aforementioned criteria:

Step 1: RSA Key Pair

This step only needs to be performed once. An RSA key pair is needed. This key pair shall not be created on the "trusted" system, but instead on a really trusted box (e. g. a trusted work station or wherever you'd trust to keep your GPG key ring). Since the private key is only needed for recovery, it shall never enter the realms of either the trusted system or the untrusted storage. Key size needs to be 4096 bits or above (we come to that later). OpenSSL usually offers key generation and separation by those commands:

EDIT: switched to PKCS#8 for the keys, being probably more resistant to brute force attacks

openssl genpkey -aes-256-cbc -algorithm RSA -pkeyopt 'rsa_keygen_bits:8192' -out private.key
openssl pkey -in private.key -out public.key -pubout

Step 2: Generate Session Secrets

For each encryption process, dedicated secrets (key, initialisation vector and salt) shall be generated:

EDIT: removed salt as per Ctulhu's comment

key=$(openssl rand -hex 32)
iv=$(openssl rand -hex 16)
hmacpw=$(openssl rand -base64 48)

Please note: I am aware that this will have the secrets unprotected in the trusted machine's memory. However, if an attacker has access to the machine in a way he can skim the backup process' memory, he probably already has access to the data to be protected by these secrets.

Step 3: Compress and Encrypt

Data shall be compressed before encryption. Compression is required anyway, so I consider it a good idea to do it before encrypting the data:

EDIT: removed salt as per Ctulhu's comment

data-generator | xz -zc | openssl enc -e -aes-256-ctr -K $key -iv $iv -out message.enc

Step 4: Generate HMAC and Pack up Keys

The last step would be to generate a HMAC of the just encrypted data, and pack it up together with the session secrets in an RSA encrypted file, using the public key for encryption:

EDIT: removed salt as per Ctulhu's comment

hmac=$(openssl dgst -sha512 -hmac $hmacpw -hex message.enc | sed 's/^.*=[[:space:]]//g')
echo "${key}:${iv}:${hmacpw}:${hmac}" | openssl rsautl -inkey public.key -pubin -encrypt -out message.key

And here it becomes obvious why the RSA key had to be that large: hex digits in shell strings are counted as one byte each, not half a byte. Therefore, the size of the key string sums up to (2x32 + 2x16 + 64 + 128 + 5) = 293 Bytes = 2344 Bits.

Again, I'm aware that exposing secrets on a command line is generally a bad idea, but given the circumstances, I do not see how this would compromise confidentiality or integrity of data which are available in plain text on said system, where an attacker could much easier compromise their privacy or integrity. However, if I would really go and implement this, I'd rather use named pipes to avoid having the secrets popping up in the process list.

Now my questions:

  1. What did I miss? Do you see any flaw or potential attack vector I haven't noticed yet?
  2. Would it be more secure to create a signature with openssl dgst -sha512 -sign private.key -out message.sig message.enc, given that this would require the private key to reside on the more or less trusted system?
Daemotron
  • 131
  • 6
  • 3
    The way I understand it, you should not supply salt to `openssl enc` when using a key. Salt is used when you are supplying a password instead of a key. – Cthulhu Aug 12 '15 at 11:13
  • 2
    It's not that "it is a good idea" to compress before encrypting; encrypted data is (usually) incompressible. Compression depends on patterns in the data; if there are patterns in encrypted data, that would provide a HUGE clue for anyone trying to break the encryption! – AMADANON Inc. Apr 15 '16 at 02:55
  • This is an old question, but some similar prior art to explore: https://www.tarsnap.com/design.html – Jonah Benton Sep 11 '16 at 14:23
  • 2 improvements come to my mind: 1. I would use the `-oaep` switch on the last encryption command, to use a better padding. 2. I would replace the MAC of the ciphertext with an RSA signature of the ciphertext (of the backupdata). the assymetrically encrypted data can be smaller than (and thus your RSA key) and storing the authentication data somewhere in the middle is a bit weird. – mat Sep 26 '16 at 14:59

1 Answers1

1
  1. For the question about what you could have missed:

At the time you encrypted the data on the server, you can use rsync to securely synchronize the data to the backup.

rsync -aHSv --del --progress ~/<encrypted-data> user@remote-backup-server:/<destination-directory>./ -n

The use of --del is to remove old stuff in the remote destination (you can safely remove that option if you want to keep all the history).

  1. For the question about security:

The advantage of doing things with rsync is that you could secure the backup server firewall to works with only some IP on some ports and use your RSA Keys with ~/.ssh/authorized_keys

  1. OpenSSL or LibreSSL?

I think that point could be interesting to dig as explain on security.stack

aurelien
  • 253
  • 2
  • 13