privacy-guides/how-to-back-up-and-encrypt-data-using-rsync-and-veracrypt-on-macos

How to back up and encrypt data using rsync and VeraCrypt on macOS

How to back up and encrypt data using rsync and VeraCrypt on macOS (see change log)

Heads-up: when using storage devices with wear-leveling (most flash storage devices), it is not possible to securely change password once it has been set (see Wear-Leveling).

Requirements

  • Computer running macOS Catalina or Big Sur
  • USB flash drive or SD card formatted using FAT (4GiB file size limit) or exFAT filesystem (see Journaling File Systems)

Caveats

  • When copy/pasting commands that start with $, strip out $ as this character is not part of the command
  • When copy/pasting commands that start with cat << "EOF", select all lines at once (from cat << "EOF" to EOF inclusively) as they are part of the same (single) command

Setup guide

Step 1: install Homebrew

/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)"
uname -m | grep amd64 && echo 'export PATH=$PATH:/opt/homebrew/bin' >> ~/.zshrc

Step 2: disable Homebrew analytics

brew analytics off

Step 3: install FUSE for macOS and GnuPG

Heads-up: if brew install --cask macfuse fails, try brew cask install macfuse (see issue).

brew install --cask macfuse
brew install gnupg

Step 4: import VeraCrypts public key

$ gpg --keyserver hkps://keys.openpgp.org --recv-keys 0x821ACD02680D16DE
gpg: key 0x821ACD02680D16DE: public key "VeraCrypt Team (2018 - Supersedes Key ID=0x54DDD393) <veracrypt@idrix.fr>" imported
gpg: Total number processed: 1
gpg:               imported: 1

Step 5: download VeraCrypt

Go to https://www.veracrypt.fr/en/Downloads.html and download latest release and associated PGP signature to ~/Downloads folder.

Step 6: verify VeraCrypt release signature (learn how here)

Replace VeraCrypt_1.24-Update7 with current release.

$ gpg --verify ~/Downloads/VeraCrypt_1.24-Update7.dmg.sig
gpg: assuming signed data in '/Users/sunknudsen/Downloads/VeraCrypt_1.24-Update7.dmg'
gpg: Signature made Sat  8 Aug 14:20:27 2020 EDT
gpg:                using RSA key 5069A233D55A0EEB174A5FC3821ACD02680D16DE
gpg: Good signature from "VeraCrypt Team (2018 - Supersedes Key ID=0x54DDD393) <veracrypt@idrix.fr>" [unknown]
gpg: WARNING: This key is not certified with a trusted signature!
gpg:          There is no indication that the signature belongs to the owner.
Primary key fingerprint: 5069 A233 D55A 0EEB 174A  5FC3 821A CD02 680D 16DE

Good signature

👍

Step 7: install VeraCrypt

$ ln -s /Applications/VeraCrypt.app/Contents/MacOS/VeraCrypt /usr/local/bin/veracrypt

$ veracrypt --text --version
VeraCrypt 1.24-Update7

VeraCrypt 1.24-Update7

👍

Step 9: set backup volume path environment variable

BACKUP_VOLUME_PATH="/Volumes/Samsung BAR/backup"

Step 10: create encrypted volume

Heads-up: volume size cannot be increased later.

Heads-up: Mac OS Extended filesystem required on macOS.

$ veracrypt --text --create "$BACKUP_VOLUME_PATH"
Volume type:
 1) Normal
 2) Hidden
Select [1]:

Enter volume size (sizeK/size[M]/sizeG): 1G

Encryption Algorithm:
 1) AES
 2) Serpent
 3) Twofish
 4) Camellia
 5) Kuznyechik
 6) AES(Twofish)
 7) AES(Twofish(Serpent))
 8) Camellia(Kuznyechik)
 9) Camellia(Serpent)
 10) Kuznyechik(AES)
 11) Kuznyechik(Serpent(Camellia))
 12) Kuznyechik(Twofish)
 13) Serpent(AES)
 14) Serpent(Twofish(AES))
 15) Twofish(Serpent)
Select [7]:

Hash algorithm:
 1) SHA-512
 2) Whirlpool
 3) SHA-256
 4) Streebog
Select [1]:

Filesystem:
 1) None
 2) FAT
 3) Mac OS Extended
 4) exFAT
 5) APFS
Select [3]:

Enter password:
Re-enter password:

Enter PIM:

Enter keyfile path [none]:

Please type at least 320 randomly chosen characters and then press Enter:


Done: 100.000%  Speed:  24 MiB/s  Left: 0 s

Error: mount_macfuse: the file system is not available (1)

Heads-up: given “FUSE for macOS” is a third-party extension, macOS prevents using the extension without explicit user consent (granted by clicking “Allow” in “System Preferences” / “Privacy & Security”).

Allow extension 1

Allow extension 2

$ veracrypt --text --create "$BACKUP_VOLUME_PATH"
Volume type:
 1) Normal
 2) Hidden
Select [1]:

Enter volume size (sizeK/size[M]/sizeG): 1G

Encryption Algorithm:
 1) AES
 2) Serpent
 3) Twofish
 4) Camellia
 5) Kuznyechik
 6) AES(Twofish)
 7) AES(Twofish(Serpent))
 8) Camellia(Kuznyechik)
 9) Camellia(Serpent)
 10) Kuznyechik(AES)
 11) Kuznyechik(Serpent(Camellia))
 12) Kuznyechik(Twofish)
 13) Serpent(AES)
 14) Serpent(Twofish(AES))
 15) Twofish(Serpent)
Select [7]:

Hash algorithm:
 1) SHA-512
 2) Whirlpool
 3) SHA-256
 4) Streebog
Select [1]:

Filesystem:
 1) None
 2) FAT
 3) Mac OS Extended
 4) exFAT
 5) APFS
Select [3]:

Enter password:
Re-enter password:

Enter PIM:

Enter keyfile path [none]:

Please type at least 320 randomly chosen characters and then press Enter:


Done: 100.000%  Speed:  24 MiB/s  Left: 0 s

The VeraCrypt volume has been successfully created.

The VeraCrypt volume has been successfully created.

👍

Step 11 (optional): mount, rename and dismount encrypted volume

By default, VeraCrypt encrypted volumes with Mac OS Extended filesystem are named “untitled”.

Mount encrypted volume

$ veracrypt --text --mount --pim 0 --keyfiles "" --protect-hidden no "$BACKUP_VOLUME_PATH" /Volumes/Backup
Enter password for /Volumes/Samsung BAR/backup:

Rename encrypted volume

$ diskutil rename "untitled" "Backup"
Volume on disk3 renamed to Backup

Volume on disk3 renamed to Backup

👍

Dismount encrypted volume

veracrypt --text --dismount "$BACKUP_VOLUME_PATH"

Step 12: create /usr/local/bin/backup.sh script

cat << EOF > /usr/local/bin/backup.sh
#! /bin/sh

set -e
set -o pipefail

function dismount()
{
  if [ -d "\$mount_point" ]; then
    veracrypt --text --dismount "\$mount_point"
  fi
}

trap dismount ERR INT

volume_path="$BACKUP_VOLUME_PATH"
mount_point="/Volumes/Backup"

veracrypt --text --mount --pim "0" --keyfiles "" --protect-hidden "no" "\$volume_path" "\$mount_point"

mkdir -p "\$mount_point/Versioning"

files=(
  "$HOME/.gnupg"
  "$HOME/.ssh"
  "$HOME/Library/Keychains"
)

for file in "\${files[@]}"; do
  rsync \\
    -axRS \\
    --backup \\
    --backup-dir \\
    "\$mount_point/Versioning" \\
    --delete \\
    --suffix="\$(date +".%F-%H%M%S")" \\
    "\$file" \\
    "\$mount_point"
done

if [ "\$(find "\$mount_point/Versioning" -type f -ctime +90)" != "" ]; then
  printf "Do you wish to prune versions older than 90 days (y or n)? "
  read -r answer
  if [ "\$answer" = "y" ]; then
    find "\$mount_point/Versioning" -type f -ctime +90 -delete
    find "\$mount_point/Versioning" -type d -empty -delete
  fi
fi

open "\$mount_point"

printf "Inspect backup and press enter"

read -r answer

dismount

printf "Generate hash (y or n)? "
read -r answer
if [ "\$answer" = "y" ]; then
  openssl dgst -sha512 "\$volume_path"
fi

printf "%s\n" "Done"
EOF
chmod +x /usr/local/bin/backup.sh

Step 13: edit /usr/local/bin/backup.sh script

vi /usr/local/bin/backup.sh

Press i to enter insert mode, edit backup script, press esc to exit insert mode and press shift+z+z to save and exit.

Step 14: create /usr/local/bin/check.sh script

cat << EOF > /usr/local/bin/check.sh
#! /bin/sh

set -e
set -o pipefail

red=\$(tput setaf 1)
normal=\$(tput sgr0)

printf "Backup hash: "

read -r previous

current=\$(openssl dgst -sha512 "$BACKUP_VOLUME_PATH")

if [ "\$current" != "\$previous" ]; then
  printf "\$red%s\$normal\n" "Integrity check failed"
  exit 1
fi

printf "%s\n" "OK"
EOF
chmod +x /usr/local/bin/check.sh

Step 15: create /usr/local/bin/restore.sh script

cat << EOF > /usr/local/bin/restore.sh
#! /bin/sh

set -e

function dismount()
{
  if [ -d "\$mount_point" ]; then
    veracrypt --text --dismount "\$mount_point"
  fi
}

trap dismount ERR INT

volume_path="$BACKUP_VOLUME_PATH"
mount_point="/Volumes/Backup"

veracrypt --text --mount --mount-options "readonly" --pim "0" --keyfiles "" --protect-hidden "no" "\$volume_path" "\$mount_point"

open "\$mount_point"

printf "Restore data and press enter"

read -r answer

dismount

printf "%s\n" "Done"
EOF
chmod +x /usr/local/bin/restore.sh

👍


Usage guide

Backup

Heads-up: store hash in safe place such as password manager (not on same device as backup).

$ backup.sh
Enter password for /Volumes/Samsung BAR/backup:
Inspect backup and press enter
Generate hash (y or n)? y
SHA512(/Volumes/Samsung BAR/backup)= 281a3b0afec6708eff9566effdfa67de357933527688dfa2dfabae5dda5b7681f0fb84f6cfec6c3f7ac20246517f18f40babbd4f337b254a55de30ff67d6dd2e
Done

Done

👍

Check

$ check.sh
Backup hash: SHA512(/Volumes/Samsung BAR/backup)= 281a3b0afec6708eff9566effdfa67de357933527688dfa2dfabae5dda5b7681f0fb84f6cfec6c3f7ac20246517f18f40babbd4f337b254a55de30ff67d6dd2e
OK

OK

👍

Restore

$ restore.sh
Enter password for /Volumes/Samsung BAR/backup:
Restore data and press enter
Done

Done

👍