Added integrity check option(--checksum)
All checks were successful
backup.sh / bash (push) Successful in 31s

This commit is contained in:
Marco Cetica 2024-04-03 08:55:06 +02:00
parent 39a15d2f2a
commit baa6f68706
Signed by: marco
GPG Key ID: 45060A949E90D0FD
5 changed files with 490 additions and 216 deletions

View File

@ -1,14 +1,9 @@
# backup.sh ![](https://github.com/ceticamarco/backup.sh/actions/workflows/backup.sh.yml/badge.svg) # backup.sh ![](https://github.com/ceticamarco/backup.sh/actions/workflows/backup.sh.yml/badge.svg)
`backup.sh` is a POSIX compliant, modular and lightweight backup utility to save and encrypt your files. `backup.sh` is a POSIX compliant, modular and lightweight backup utility to save and encrypt your files.
This tool is intended to be used on small scale UNIX environments such as VPS, personal servers and This tool is intended to be used on small scale UNIX environments such as VPS, personal servers and
workstations. `backup.sh` uses [rsync](https://linux.die.net/man/1/rsync), [tar](https://linux.die.net/man/1/tar) workstations. `backup.sh` uses [rsync](https://linux.die.net/man/1/rsync), [tar](https://linux.die.net/man/1/tar),
and [gpg](https://linux.die.net/man/1/gpg) to copy, compress and encrypt the backup. [gpg](https://linux.die.net/man/1/gpg) and [sha256sum](https://linux.die.net/man/1/sha256sum)
to copy, compress, encrypt the backup and verify the backup.
`backup.sh` works under the following operating systems:
- GNU/Linux;
- OpenBSD
- FreeBSD;
- Apple MacOS.
## Installation ## Installation
`backup.sh` consists in a single source file, to install it you can copy the script wherever you want. `backup.sh` consists in a single source file, to install it you can copy the script wherever you want.
@ -30,18 +25,23 @@ To show the available options, you can run `backup.sh --help`, which will print
```text ```text
backup.sh - POSIX compliant, modular and lightweight backup utility. backup.sh - POSIX compliant, modular and lightweight backup utility.
Syntax: ./backup.sh [-b|-e|-h] Syntax: ./backup.sh [-b|-c|-e|-h]
options: options:
-b|--backup SOURCES DEST PASS Backup folders from SOURCES file. -b|--backup SOURCES DEST PASS Backup folders from SOURCES file.
-e|--extract ARCHIVE PASS Extract ARCHIVE using PASS. -c|--checksum Generate/check SHA256 of a backup.
-h|--help Show this helper. -e|--extract ARCHIVE PASS Extract ARCHIVE using PASS.
-h|--help Show this helper.
General help with the software: https://github.com/ceticamarco/backup.sh
Report bugs to: Marco Cetica(<email@marcocetica.com>)
``` ```
As you can see, `backup.sh` supports two options: **backup creation** and **backup extraction**, the former requires As you can see, `backup.sh` supports three options: **backup creation**, **backup extraction** and **checksum** to verify the
root permissions, while the latter does not. Let us see them in details. integrity of a backup. The first option requires
root permissions, while the second one does not. The checksum option must be used in combination of one of the previous options.
### Backup creation ### Backup creation
To specify the directories to backup, `backup.sh` uses an associative array To specify the directories to back up, `backup.sh` uses an associative array
defined in a text file(called _sources file_) with the following syntax: defined in a text file(called _sources file_) with the following syntax:
```text ```text
@ -68,7 +68,7 @@ backup-ssh-<YYYYMMDD>
``` ```
You can add as many entries as you want, just be sure to use the proper syntax. In particular, You can add as many entries as you want, just be sure to use the proper syntax. In particular,
the _sources file_, **should not** includes: the _sources file_, **should not** include:
- Spaces between the label and the equal sign; - Spaces between the label and the equal sign;
- Empty lines; - Empty lines;
- Comments. - Comments.
@ -88,19 +88,26 @@ In the previous example, this would be:
$> sudo ./backup.sh --backup sources.bk /home/john badpw1234 $> sudo ./backup.sh --backup sources.bk /home/john badpw1234
``` ```
You can also tell `backup.sh` to generate a SHA256 file containing the hash of each file using the `-c` option.
In the previous example, this would be:
```sh
$> sudo ./backup.sh --checksum --backup sources.bk /home/john badpw1234
```
The backup utility will begin to copy the files defined in the _sources file_: The backup utility will begin to copy the files defined in the _sources file_:
```text ```text
Copying nginx(1/2) Copying nginx(1/2)
Copying ssh(2/2) Copying ssh(2/2)
Compressing backup... Compressing backup...
Encrypting backup... Encrypting backup...
File name: /home/marco/backup-<HOSTNAME>-<YYYYMMDD>.tar.gz.enc File name: /home/john/backup-<HOSTNAME>-<YYYYMMDD>.tar.gz.enc
Checksum file: /home/john/backup-<HOSTNAME>-<YYYYMMDD>.sha256
File size: 7336400696(6.9G) File size: 7336400696(6.9G)
File hash: 0e75ca393117f389d9e8edfea7106d98
Elapsed time: 259 seconds. Elapsed time: 259 seconds.
``` ```
After that, you will find the final backup archive in `/home/john/backup-<HOSTNAME>-<YYYYMMDD>.tar.gz.enc`. After that, you will find the backup archive and the checksum file in
`/home/john/backup-<HOSTNAME>-<YYYYMMDD>.tar.gz.enc` and `/home/john/backup-<HOSTNAME>-<YYYYMMDD>.sha256`, respectively.
You can also use `backup.sh` from a crontab rule: You can also use `backup.sh` from a crontab rule:
```sh ```sh
@ -114,7 +121,8 @@ key is stored in a local file(with fixed permissions) to avoid password leaking
adopt this practice while using the `--extract` option to avoid password leaking in shell history. adopt this practice while using the `--extract` option to avoid password leaking in shell history.
### Backup extraction ### Backup extraction
`backup.sh` can also extract the encrypted backup archive using the following syntax: `backup.sh` can also be used to extract the encrypted backup as well to verify the integrity
of the backup data. To do so, use the following commands:
```sh ```sh
$> ./backup.sh --extract <ENCRYPTED_ARCHIVE> <ARCHIVE_PASSWORD> $> ./backup.sh --extract <ENCRYPTED_ARCHIVE> <ARCHIVE_PASSWORD>
@ -128,16 +136,31 @@ For instance:
$> ./backup.sh --extract backup-<hostname>-<YYYYMMDD>.tar.gz.enc badpw1234 $> ./backup.sh --extract backup-<hostname>-<YYYYMMDD>.tar.gz.enc badpw1234
``` ```
This will create a new folder called `backup.sh.tmp` in your local directory. Be sure to rename any directory This will create a new folder called `backup.sh.tmp` in your local directory with the following content:
with that name to avoid collisions. From the previous example, you should have the following directories:
```text ```text
backup-nginx-<YYYYMMDD> backup-nginx-<YYYYMMDD>
backup-ssh-<YYYYMMDD> backup-ssh-<YYYYMMDD>
``` ```
**note:**: be sure to rename any directory with that name to avoid collisions.
Instead, if you also want to verify the integrity of the backup data, use the following commands:
```sh
$> ./backup.sh --checksum --extract <ENCRYPTED_ARCHIVE> <ARCHIVE_PASSWORD> <CHECKSUM_ABSOLUTE_PATH>
```
For instance:
```sh
$> ./backup.sh --checksum --extract backup-<hostname>-<YYYYMMDD>.tar.gz.enc badpw1234 $PWD/backup-<hostname>-<YYYYMMDD>.sha256
```
**note:** be sure to provide the ABSOLUTE PATH of the checksum file.
## How does backup.sh work? ## How does backup.sh work?
**backup.sh** uses _rsync_ to copy the files, _tar_ to compress the backup and _gpg_ to encrypt it. **backup.sh** uses _rsync_ to copy the files, _tar_ to compress the backup, _gpg_ to encrypt it and
_sha256sum_ to verify it.
By default, rsync is being used with the following parameters: By default, rsync is being used with the following parameters:
``` ```
@ -153,10 +176,15 @@ That is:
- q: quiet mode: reduces the amount of information rsync produces; - q: quiet mode: reduces the amount of information rsync produces;
- delete: delete mode: forces rsync to delete any extraneous files at the destination dir. - delete: delete mode: forces rsync to delete any extraneous files at the destination dir.
If specified(`--checksum` option), `backup.sh` can also generate the checksum of each file of the backup.
To do so, it uses `sha256sum(1)` to compute the hash of every single file using the SHA256 hashing algorithm.
The checksum file contains nothing but the checksums of the files, no other information about the files stored
on the backup archive is exposed on the unencrypted checksum file. This may be an issue if you want plausible
deniability(see privacy section for more information).
After that the backup folder is being encrypted using gpg. By default, it is used with the following parameters: After that the backup folder is being encrypted using gpg. By default, it is used with the following parameters:
``` ```
$> gpg -a \ $> gpg -a \
--symmetric \ --symmetric \
@ -177,6 +205,18 @@ This command encrypts the backup using the AES-256 symmetric encryption algorith
- `--output`: Specify output file; - `--output`: Specify output file;
- `$INPUT`: Specify input file. - `$INPUT`: Specify input file.
## Plausible Deniability
While `backup.sh` provide some pretty strong security against bruteforce attack(assuming a strong passphrase is being used)
it should by no means considered a viable tool against a cryptanalysis investigation. Many of the copying, compressing and
encrypting operations made by `backup.sh` during the backup process can be used to invalidate plausible deniability.
In particular, you should pay attention to the following details:
1. The `--checksum` option generates an **UNENCRYPTED** checksum file containing the _digests_ of **EVERY**
file in your backup archive. If your files are known to your adversary(e.g., a banned book), they may use a rainbow table attack to
determine whether you own a given file, voiding your plausible deniability;
2. Since `backup.sh` is essentially a set of shell commands, an eavesdropper could monitor the whole backup process to extract
the name of the files or the encryption password.
## Unit tests ## Unit tests
`backup.sh` provides some unit tests inside the `tests.sh` script. This script generates some dummy files inside the following `backup.sh` provides some unit tests inside the `tests.sh` script. This script generates some dummy files inside the following
directories: directories:

115
backup.sh
View File

@ -13,19 +13,23 @@
# logs=/var/log/ # logs=/var/log/
# #
# After that you can launch the script with(sample usage): # After that you can launch the script with(sample usage):
# sudo ./backup.sh --backup sources.bk /home/john badpw1234 # sudo ./backup.sh --checksum --backup sources.bk /home/john badpw1234
# #
# This will create an encrypted tar archive(password: 'badpw1234') # This will create an encrypted tar archive(password: 'badpw1234')
# in '/home/john/backup-<hostname>-<YYYMMDD>.tar.gz.enc' containing # in '/home/john/backup-<hostname>-<YYYYMMDD>.tar.gz.enc' containing
# the following three directories: # the following three directories:
# backup-nginx-<YYYYMMDD> # backup-nginx-<YYYYMMDD>
# backup-ssh-<YYYYMMDD> # backup-ssh-<YYYYMMDD>
# backup-logs-<YYYYMMDD> # backup-logs-<YYYYMMDD>
# #
# You can then decrypt it using: # as well as a SHA256 file('/home/john/backup-<hostname>-<YYYYMMDD>.sha256')
# ./backup.sh --extract backup-<hostname>-<YYYMMDD>.tar.gz.enc badpw1234 # containing the file hashes of the backup.
# #
# You can read the full guide on https://github.com/ice-bit/backup.sh # You can then decrypt it using:
# ./backup.sh --checksum --extract backup-<hostname>-<YYYYMMDD>.tar.gz.enc badpw1234 $PWD/backup-<hostname>-<YYYYMMDD>.sha256
# which will also check the integrity of the backup(optional feature).
#
# You can read the full guide on https://github.com/ceticamarco/backup.sh
# or on the manual page. # or on the manual page.
# Copyright (c) 2018,2023,2024 Marco Cetica <email@marcocetica.com> # Copyright (c) 2018,2023,2024 Marco Cetica <email@marcocetica.com>
# #
@ -47,29 +51,23 @@ checkdeps() {
fi fi
} }
checksum() { # $1: sources.bk file
BACKUP_SH_FILENAME="$1" # $2: output path
BACKUP_SH_OS="$(uname | tr '[:lower:]' '[:upper:]')" # $3: password
# $4: compute sha256(0,1)
if [ "$BACKUP_SH_OS" = "LINUX" ]; then
RES="$(md5sum "$BACKUP_SH_FILENAME" | awk '{print $1}')"
else
RES="$(md5 -q "$BACKUP_SH_FILENAME")"
fi
echo "$RES"
}
make_backup() { make_backup() {
BACKUP_SH_SOURCES_PATH="$1" BACKUP_SH_SOURCES_PATH="$1"
BACKUP_SH_OUTPATH="$2" BACKUP_SH_OUTPATH="$2"
BACKUP_SH_PASS="$3" BACKUP_SH_PASS="$3"
BACKUP_SH_SHA256="$4"
BACKUP_SH_COMMAND="rsync -aPhrq --delete" BACKUP_SH_COMMAND="rsync -aPhrq --delete"
BACKUP_SH_DATE="$(date +'%Y%m%d')" BACKUP_SH_DATE="$(date +'%Y%m%d')"
BACKUP_SH_FOLDER="backup.sh.tmp" BACKUP_SH_FOLDER="backup.sh.tmp"
BACKUP_SH_OUTPUT="$BACKUP_SH_OUTPATH/$BACKUP_SH_FOLDER" BACKUP_SH_OUTPUT="$BACKUP_SH_OUTPATH/$BACKUP_SH_FOLDER"
BACKUP_SH_START_TIME="$(date +%s)" BACKUP_SH_START_TIME="$(date +%s)"
BACKUP_SH_FILENAME="$BACKUP_SH_OUTPATH/backup-$(uname -n)-$BACKUP_SH_DATE.tar.gz.enc" BACKUP_SH_FILENAME="$BACKUP_SH_OUTPATH/backup-$(uname -n)-$BACKUP_SH_DATE.tar.gz.enc"
BACKUP_SH_CHECKSUM_FILE="$BACKUP_SH_OUTPATH/backup-$(uname -n)-$BACKUP_SH_DATE.sha256"
# Check for root permissions # Check for root permissions
if [ "$(id -u)" -ne 0 ]; then if [ "$(id -u)" -ne 0 ]; then
@ -96,6 +94,13 @@ make_backup() {
mkdir -p "$BACKUP_SH_SUBDIR" mkdir -p "$BACKUP_SH_SUBDIR"
printf "Copying %s(%s/%s)\n" "$label" "$BACKUP_SH_PROGRESS" "$BACKUP_SH_TOTAL" printf "Copying %s(%s/%s)\n" "$label" "$BACKUP_SH_PROGRESS" "$BACKUP_SH_TOTAL"
# Compute SHA256 of all files of the current directory
if [ "$BACKUP_SH_SHA256" -eq 1 ]; then
find "$path" -type f -exec sha256sum {} + | sort -k 2 | awk '{print $1}' >> "$BACKUP_SH_CHECKSUM_FILE"
fi
# Copy files
$BACKUP_SH_COMMAND "$path" "$BACKUP_SH_SUBDIR" $BACKUP_SH_COMMAND "$path" "$BACKUP_SH_SUBDIR"
BACKUP_SH_PROGRESS=$((BACKUP_SH_PROGRESS+1)) BACKUP_SH_PROGRESS=$((BACKUP_SH_PROGRESS+1))
done < "$BACKUP_SH_SOURCES_PATH" done < "$BACKUP_SH_SOURCES_PATH"
@ -124,20 +129,24 @@ make_backup() {
BACKUP_SH_END_TIME="$(date +%s)" BACKUP_SH_END_TIME="$(date +%s)"
BACKUP_SH_FILE_SIZE="$(find "$BACKUP_SH_FILENAME" -exec ls -l {} \; | awk '{print $5}')" BACKUP_SH_FILE_SIZE="$(find "$BACKUP_SH_FILENAME" -exec ls -l {} \; | awk '{print $5}')"
BACKUP_SH_FILE_SIZE_H="$(find "$BACKUP_SH_FILENAME" -exec ls -lh {} \; | awk '{print $5}')" BACKUP_SH_FILE_SIZE_H="$(find "$BACKUP_SH_FILENAME" -exec ls -lh {} \; | awk '{print $5}')"
BACKUP_SH_HASH="$(checksum "$BACKUP_SH_FILENAME")"
echo "File name: $BACKUP_SH_FILENAME" echo "File name: $BACKUP_SH_FILENAME"
[ "$BACKUP_SH_SHA256" -eq 1 ] && { echo "Checksum file: $BACKUP_SH_CHECKSUM_FILE"; }
echo "File size: $BACKUP_SH_FILE_SIZE($BACKUP_SH_FILE_SIZE_H)" echo "File size: $BACKUP_SH_FILE_SIZE($BACKUP_SH_FILE_SIZE_H)"
echo "File hash: $BACKUP_SH_HASH"
printf "Elapsed time: %s seconds.\n" "$((BACKUP_SH_END_TIME - BACKUP_SH_START_TIME))" printf "Elapsed time: %s seconds.\n" "$((BACKUP_SH_END_TIME - BACKUP_SH_START_TIME))"
} }
# $1: archive file
# $2: archive password
# $3: sha256 file(optional)
extract_backup() { extract_backup() {
BACKUP_SH_ARCHIVE_PATH="$1" BACKUP_SH_ARCHIVE_PATH="$1"
BACKUP_SH_ARCHIVE_PW="$2" BACKUP_SH_ARCHIVE_PW="$2"
BACKUP_SH_SHA256_FILE="$3"
# Decrypt the archive # Decrypt the archive
gpg -a \ gpg -a \
--quiet \
--decrypt \ --decrypt \
--no-symkey-cache \ --no-symkey-cache \
--pinentry-mode=loopback \ --pinentry-mode=loopback \
@ -148,7 +157,20 @@ extract_backup() {
# Extract archive # Extract archive
tar -xzf backup.sh.tar.gz 1> /dev/null 2>&1 tar -xzf backup.sh.tar.gz 1> /dev/null 2>&1
# Remove temporary files # If specified, use SHA256 file to compute checksum of files
if [ -n "$BACKUP_SH_SHA256_FILE" ]; then
for file in $(find "backup.sh.tmp" -type f | sort -k 2); do
# Compute sha256 for current file
sha256="$(sha256sum "$file" | awk '{print $1}')"
# Check if checksum file contains hash
if ! grep -wq "$sha256" "$BACKUP_SH_SHA256_FILE"; then
printf "[FATAL] - integrity error for '%s'.\n" "$file"
rm -rf backup.sh.tar.gz backup.sh.tmp
exit 1
fi
done
fi
rm -rf backup.sh.tar.gz rm -rf backup.sh.tar.gz
} }
@ -158,13 +180,14 @@ helper() {
cat <<EOF cat <<EOF
backup.sh - POSIX compliant, modular and lightweight backup utility. backup.sh - POSIX compliant, modular and lightweight backup utility.
Syntax: $CLI_NAME [-b|-e|-h] Syntax: $CLI_NAME [-b|-c|-e|-h]
options: options:
-b|--backup SOURCES DEST PASS Backup folders from SOURCES file. -b|--backup SOURCES DEST PASS Backup folders from SOURCES file.
-e|--extract ARCHIVE PASS Extract ARCHIVE using PASS. -c|--checksum Generate/check SHA256 of a backup.
-h|--help Show this helper. -e|--extract ARCHIVE PASS Extract ARCHIVE using PASS.
-h|--help Show this helper.
General help with the software: https://github.com/ice-bit/backup.sh General help with the software: https://github.com/ceticamarco/backup.sh
Report bugs to: Marco Cetica(<email@marcocetica.com>) Report bugs to: Marco Cetica(<email@marcocetica.com>)
EOF EOF
} }
@ -179,6 +202,7 @@ main() {
exit 1 exit 1
fi fi
CHECKSUM_FLAG=0
# Parse CLI arguments # Parse CLI arguments
while [ $# -gt 0 ]; do while [ $# -gt 0 ]; do
case $1 in case $1 in
@ -192,19 +216,46 @@ main() {
echo "For more informatio, try --help" echo "For more informatio, try --help"
exit 1 exit 1
fi fi
make_backup "$BACKUP_SH_SOURCES_PATH" "$BACKUP_SH_OUTPATH" "$BACKUP_SH_PASSWORD"
if [ "$CHECKSUM_FLAG" -eq 1 ]; then
make_backup "$BACKUP_SH_SOURCES_PATH" "$BACKUP_SH_OUTPATH" "$BACKUP_SH_PASSWORD" 1
else
make_backup "$BACKUP_SH_SOURCES_PATH" "$BACKUP_SH_OUTPATH" "$BACKUP_SH_PASSWORD" 0
fi
exit 0 exit 0
;; ;;
-c|--checksum)
[ $# -eq 1 ] && { echo "Use this option with '--backup' or '--extract'"; exit 1; }
CHECKSUM_FLAG=1
shift 1
;;
-e|--extract) -e|--extract)
BACKUP_SH_ARCHIVE_PATH="$2" BACKUP_SH_ARCHIVE_PATH="$2"
BACKUP_SH_ARCHIVE_PW="$3" BACKUP_SH_ARCHIVE_PW="$3"
BACKUP_SH_SHA256_FILE="$4"
if [ -z "$BACKUP_SH_ARCHIVE_PATH" ] || [ -z "$BACKUP_SH_ARCHIVE_PW" ]; then if [ "$CHECKSUM_FLAG" -eq 1 ]; then
echo "Please, specify an encrypted archive and a password." if [ -z "$BACKUP_SH_ARCHIVE_PATH" ] || [ -z "$BACKUP_SH_ARCHIVE_PW" ] || [ -z "$BACKUP_SH_SHA256_FILE" ]; then
echo "For more informatio, try --help" echo "Please, specify an encrypted archive, a password and a SHA256 file."
exit 1 echo "For more informatio, try --help"
exit 1
fi
else
if [ -z "$BACKUP_SH_ARCHIVE_PATH" ] || [ -z "$BACKUP_SH_ARCHIVE_PW" ]; then
echo "Please, specify an encrypted archive and a password."
echo "For more informatio, try --help"
exit 1
fi
fi fi
extract_backup "$BACKUP_SH_ARCHIVE_PATH" "$BACKUP_SH_ARCHIVE_PW"
if [ "$CHECKSUM_FLAG" -eq 1 ]; then
[ -e "$BACKUP_SH_SHA256_FILE" ] || { echo "Checksum file does not exist"; exit 1; }
extract_backup "$BACKUP_SH_ARCHIVE_PATH" "$BACKUP_SH_ARCHIVE_PW" "$BACKUP_SH_SHA256_FILE"
else
extract_backup "$BACKUP_SH_ARCHIVE_PATH" "$BACKUP_SH_ARCHIVE_PW"
fi
exit 0 exit 0
;; ;;
-h|--help) -h|--help)

View File

@ -1,265 +1,406 @@
.\" Automatically generated by Pandoc 3.1.8 .\" Automatically generated by Pandoc 2.17.1.1
.\" .\"
.TH "backup.sh" "1" "February 27, 2024" "Marco Cetica" "General Commands Manual" .\" Define V font for inline verbatim, using C font in formats
.\" that render this, and otherwise B font.
.ie "\f[CB]x\f[]"x" \{\
. ftr V B
. ftr VI BI
. ftr VB B
. ftr VBI BI
.\}
.el \{\
. ftr V CR
. ftr VI CI
. ftr VB CB
. ftr VBI CBI
.\}
.TH "backup.sh" "1" "April 3, 2024" "Marco Cetica" "General Commands Manual"
.hy
.SH NAME .SH NAME
.PP
\f[B]backup.sh\f[R] - POSIX compliant, modular and lightweight backup \f[B]backup.sh\f[R] - POSIX compliant, modular and lightweight backup
utility to save and encrypt your files. utility to save and encrypt your files.
.SH SYNOPSIS .SH SYNOPSIS
.IP .IP
.EX .nf
Syntax: backup.sh [-b|-e|-h] \f[C]
Syntax: ./backup.sh [-b|-c|-e|-h]
options: options:
-b|--backup SOURCES DEST PASS Backup folders from SOURCES file. -b|--backup SOURCES DEST PASS Backup folders from SOURCES file.
-e|--extract ARCHIVE PASS Extract ARCHIVE using PASS. -c|--checksum Generate/check SHA256 of a backup.
-h|--help Show this helper. -e|--extract ARCHIVE PASS Extract ARCHIVE using PASS.
.EE -h|--help Show this helper.
\f[R]
.fi
.SH DESCRIPTION .SH DESCRIPTION
.PP
\f[B]backup.sh\f[R] is a POSIX compliant, modular and lightweight backup \f[B]backup.sh\f[R] is a POSIX compliant, modular and lightweight backup
utility to save and encrypt your files. utility to save and encrypt your files.
This tool is intended to be used on small scale UNIX environment such as This tool is intended to be used on small scale UNIX environment such as
VPS, small servers and workstations. VPS, small servers and workstations.
\f[B]backup.sh\f[R] uses \f[I]rsync\f[R], \f[I]tar\f[R] and \f[B]backup.sh\f[R] uses \f[I]rsync\f[R], \f[I]tar\f[R],
\f[I]gpg\f[R] to copy, compress and encrypt the backup. \f[I]sha256sum\f[R] and \f[I]gpg\f[R] to copy, compress, verify and
encrypt the backup.
.SH OPTIONS .SH OPTIONS
\f[B]backup.sh\f[R] supports two options: \f[I]backup creation\f[R] and .PP
\f[I]backup extraction\f[R]. \f[B]backup.sh\f[R] supports three options: \f[B]backup creation\f[R],
The former requires root permissions, while the latter does not. \f[B]backup extraction\f[R] and \f[B]checksum\f[R] to verify the
Let us see them in details: integrity of a backup.
The first option requires root permissions, while the second one does
not.
The checksum option must be used in combination of one of the previous
options.
.SS Backup creation .SS Backup creation
To specify the directories to backup, \f[B]backup.sh\f[R] uses an
associative array defined in a text file(called sources file) with the
following syntax:
.IP
.EX
<LABEL>=<PATH>
.EE
.PP .PP
Where \f[CR]<LABEL>\f[R] is the name of the backup and \f[CR]<PATH>\f[R] To specify the directories to back up, \f[V]backup.sh\f[R] uses an
is its path. associative array defined in a text file(called \f[I]sources file\f[R])
For example, if you want to back up \f[I]/etc/nginx\f[R] and
\f[I]/etc/ssh\f[R], add the following entries to the sources file:
.IP
.EX
nginx=/etc/nginx/
ssh=/etc/ssh/
.EE
.PP
\f[B]backup.sh\f[R] will create two folders inside the backup archive
with the following syntax: with the following syntax:
.IP .IP
.EX .nf
\f[C]
<LABEL>=<PATH>
\f[R]
.fi
.PP
Where \f[V]<LABEL>\f[R] is the name of the backup and \f[V]<PATH>\f[R]
is its path.
For example, if you want to back up \f[V]/etc/nginx\f[R] and
\f[V]/etc/ssh\f[R], add the following entries to the \f[I]sources
file\f[R]:
.IP
.nf
\f[C]
nginx=/etc/nginx/
ssh=/etc/ssh/
\f[R]
.fi
.PP
\f[V]backup.sh\f[R] will create two folders inside the backup archive
with the following syntax:
.IP
.nf
\f[C]
backup-<LABEL>-<YYYYMMDD> backup-<LABEL>-<YYYYMMDD>
.EE \f[R]
.fi
.PP .PP
In the previous example, this would be: In the previous example, this would be:
.IP .IP
.EX .nf
\f[C]
backup-nginx-<YYYYMMDD> backup-nginx-<YYYYMMDD>
backup-ssh-<YYYYMMDD> backup-ssh-<YYYYMMDD>
.EE \f[R]
.fi
.PP .PP
You can add as many entries as you want, just be sure to use the proper You can add as many entries as you want, just be sure to use the proper
syntax. syntax.
In particular, the sources file, \f[I]should not\f[R] includes: In particular, the \f[I]sources file\f[R], \f[B]should not\f[R] include:
.IP - Spaces between the label and the equal sign;
.EX .PD 0
- Spaces between the label and the equal sign; .P
- Empty lines; .PD
- Comments. - Empty lines;
.EE .PD 0
.P
.PD
- Comments.
.PP .PP
You can find a sample sources file at \f[CR]sources.bk\f[R](or at You can find a sample \f[I]sources file\f[R] at \f[V]sources.bk\f[R](or
\f[CR]/usr/local/etc/sources.bk\f[R]). at \f[V]/usr/local/etc/sources.bk\f[R]).
.PP .PP
After having defined the sources file, you can invoke After having defined the \f[I]sources file\f[R], you can invoke
\f[B]backup.sh\f[R] using the following syntax: \f[V]backup.sh\f[R] using the following syntax:
.IP .IP
.EX .nf
\f[C]
$> sudo ./backup.sh --backup <SOURCES_FILE> <DEST> <ENCRYPTION_PASSWORD> $> sudo ./backup.sh --backup <SOURCES_FILE> <DEST> <ENCRYPTION_PASSWORD>
.EE \f[R]
.fi
.PP .PP
Where \f[CR]<SOURCES_FILE>\f[R] is the \f[I]sources file\f[R], Where \f[V]<SOURCES_FILE>\f[R] is the \f[I]sources file\f[R],
\f[CR]<DEST>\f[R] is the absolute path of the output of the backup \f[V]<DEST>\f[R] is the absolute path of the output of the backup
\f[I]without trailing slashes\f[R] and \f[CR]<ENCRYPTION_PASSWORD>\f[R] \f[B]without trailing slashes\f[R] and \f[V]<ENCRYPTION_PASSWORD>\f[R]
is the password to encrypt the compressed archive. is the password to encrypt the compressed archive.
.PP .PP
In the previous example, this would be: In the previous example, this would be:
.IP .IP
.EX .nf
\f[C]
$> sudo ./backup.sh --backup sources.bk /home/john badpw1234 $> sudo ./backup.sh --backup sources.bk /home/john badpw1234
.EE \f[R]
.fi
.PP .PP
The backup utility will begin to copy the files defined in the sources You can also tell \f[V]backup.sh\f[R] to generate a SHA256 file
file: containing the hash of each file using the \f[V]-c\f[R] option.
In the previous example, this would be:
.IP .IP
.EX .nf
\f[C]
$> sudo ./backup.sh --checksum --backup sources.bk /home/john badpw1234
\f[R]
.fi
.PP
The backup utility will begin to copy the files defined in the
\f[I]sources file\f[R]:
.IP
.nf
\f[C]
Copying nginx(1/2) Copying nginx(1/2)
Copying ssh(2/2) Copying ssh(2/2)
Compressing backup... Compressing backup...
Encrypting backup... Encrypting backup...
File name: /home/marco/backup-<HOSTNAME>-<YYYYMMDD>.tar.gz.enc File name: /home/john/backup-<HOSTNAME>-<YYYYMMDD>.tar.gz.enc
Checksum file: /home/john/backup-<HOSTNAME>-<YYYYMMDD>.sha256
File size: 7336400696(6.9G) File size: 7336400696(6.9G)
File hash: 0e75ca393117f389d9e8edfea7106d98
Elapsed time: 259 seconds. Elapsed time: 259 seconds.
.EE \f[R]
.fi
.PP .PP
After that, you will find the final backup archive in After that, you will find the backup archive and the checksum file in
\f[CR]/home/john/backup-<HOSTNAME>-<YYYYMMDD>.tar.gz.enc\f[R]. \f[V]/home/john/backup-<HOSTNAME>-<YYYYMMDD>.tar.gz.enc\f[R] and
\f[V]/home/john/backup-<HOSTNAME>-<YYYYMMDD>.sha256\f[R], respectively.
.PP .PP
You can also use \f[B]backup.sh\f[R] from a crontab rule: You can also use \f[V]backup.sh\f[R] from a crontab rule:
.IP .IP
.EX .nf
\f[C]
$> sudo crontab -e $> sudo crontab -e
30 03 * * 6 EKEY=$(cat /home/john/.ekey) sh -c \[aq]/usr/local/bin/backup.sh -b /usr/local/etc/sources.bk /home/john $EKEY\[aq] > /dev/null 2>&1 30 03 * * 6 EKEY=$(cat /home/john/.ekey) sh -c \[aq]/usr/local/bin/backup.sh -b /usr/local/etc/sources.bk /home/john $EKEY\[aq] > /dev/null 2>&1
.EE \f[R]
.fi
.PP .PP
This will automatically run \f[B]backup.sh\f[R] every Saturday morning This will automatically run \f[V]backup.sh\f[R] every Saturday morning
at 03:30 AM. at 03:30 AM.
In the example above, the encryption key is stored in a local file(with In the example above, the encryption key is stored in a local file(with
fixed permissions) to avoid password leaking in crontab logs. fixed permissions) to avoid password leaking in crontab logs.
You can also adopt this practice while using the \f[CR]--extract\f[R] You can also adopt this practice while using the \f[V]--extract\f[R]
option to avoid password leaking in shell history. option to avoid password leaking in shell history.
.SS Backup extraction .SS Backup extraction
\f[B]backup.sh\f[R] can also extract the encrypted backup archive using
the following syntax:
.IP
.EX
$> ./backup.sh --extract <ENCRYPTED_ARCHIVE> <ARCHIVE_PASSWORD>
.EE
.PP .PP
Where \f[CR]<ENCRYPTED_ARCHIVE>\f[R] is the encrypted backup and \f[B]backup.sh\f[R] can also be used to extract the encrypted backup as
\f[CR]<ARCHIVE_PASSWORD>\f[R] is the backup password. well to verify the integrity of the backup data.
To do so, use the following commands:
.IP
.nf
\f[C]
$> ./backup.sh --extract <ENCRYPTED_ARCHIVE> <ARCHIVE_PASSWORD>
\f[R]
.fi
.PP
Where \f[V]<ENCRYPTED_ARCHIVE>\f[R] is the encrypted backup and
\f[V]<ARCHIVE_PASSWORD>\f[R] is the backup password.
.PP .PP
For instance: For instance:
.IP .IP
.EX .nf
\f[C]
$> ./backup.sh --extract backup-<hostname>-<YYYYMMDD>.tar.gz.enc badpw1234 $> ./backup.sh --extract backup-<hostname>-<YYYYMMDD>.tar.gz.enc badpw1234
.EE \f[R]
.fi
.PP .PP
This will create a new folder called \f[CR]backup.sh.tmp\f[R] in your This will create a new folder called \f[V]backup.sh.tmp\f[R] in your
local directory. local directory with the following content:
Be sure to rename any directory with that name to avoid collisions.
From the previous example, you should have the following directories:
.IP .IP
.EX .nf
\f[C]
backup-nginx-<YYYYMMDD> backup-nginx-<YYYYMMDD>
backup-ssh-<YYYYMMDD> backup-ssh-<YYYYMMDD>
.EE \f[R]
.fi
.PP
\f[B]note:\f[R]: be sure to rename any directory with that name to avoid
collisions.
.PP
Instead, if you also want to verify the integrity of the backup data,
use the following commands:
.IP
.nf
\f[C]
$> ./backup.sh --checksum --extract <ENCRYPTED_ARCHIVE> <ARCHIVE_PASSWORD> <CHECKSUM_ABSOLUTE_PATH>
\f[R]
.fi
.PP
For instance:
.IP
.nf
\f[C]
$> ./backup.sh --checksum --extract backup-<hostname>-<YYYYMMDD>.tar.gz.enc badpw1234 $PWD/backup-<hostname>-<YYYYMMDD>.sha256
\f[R]
.fi
.PP
\f[B]note:\f[R] be sure to provide the ABSOLUTE PATH of the checksum
file.
.SS How does backup.sh work? .SS How does backup.sh work?
.PP
\f[B]backup.sh\f[R] uses \f[I]rsync\f[R] to copy the files, \f[B]backup.sh\f[R] uses \f[I]rsync\f[R] to copy the files,
\f[I]tar\f[R] to compress the backup and \f[I]gpg\f[R] to encrypt it. \f[I]tar\f[R] to compress the backup, \f[I]gpg\f[R] to encrypt it and
\f[I]sha256sum\f[R] to verify it.
By default, rsync is being used with the following parameters: By default, rsync is being used with the following parameters:
.IP .IP
.EX .nf
\f[C]
$> rsync -aPhrq --delete $> rsync -aPhrq --delete
.EE \f[R]
.fi
.PP .PP
That is: That is:
.IP .IP
.EX .nf
\f[C]
- a: archive mode: rsync copies files recursively while preserving as much metadata as possible; - a: archive mode: rsync copies files recursively while preserving as much metadata as possible;
- P: progress/partial: allows rsync to resume interrupted transfers and to shows progress information; - P: progress/partial: allows rsync to resume interrupted transfers and to shows progress information;
- h: human readable output, rsync shows output numbers in a more readable way; - h: human readable output, rsync shows output numbers in a more readable way;
- r: recursive mode: forces rsync to copy directories and their content; - r: recursive mode: forces rsync to copy directories and their content;
- q: quiet mode: reduces the amount of information rsync produces; - q: quiet mode: reduces the amount of information rsync produces;
- delete: delete mode: forces rsync to delete any extraneous files at the destination dir. - delete: delete mode: forces rsync to delete any extraneous files at the destination dir.
.EE \f[R]
.fi
.PP
If specified(\f[V]--checksum\f[R] option), \f[V]backup.sh\f[R] can also
generate the checksum of each file of the backup.
To do so, it uses \f[V]sha256sum(1)\f[R] to compute the hash of every
single file using the SHA256 hashing algorithm.
The checksum file contains nothing but the checksums of the files, no
other information about the files stored on the backup archive is
exposed on the unencrypted checksum file.
This may be an issue if you want plausible deniability(see privacy
section for more information).
.PP .PP
After that the backup folder is being encrypted using gpg. After that the backup folder is being encrypted using gpg.
By default, it is used with the following parameters: By default, it is used with the following parameters:
.IP .IP
.EX .nf
\f[C]
$> gpg -a \[rs] $> gpg -a \[rs]
--symmetric \[rs] --symmetric \[rs]
--cipher-algo=AES256 \[rs] --cipher-algo=AES256 \[rs]
--no-symkey-cache \[rs] --no-symkey-cache \[rs]
--pinentry-mode=loopback \[rs] --pinentry-mode=loopback \[rs]
--batch --passphrase-fd \[dq]$PASSWORD\[dq] \[rs] --batch --passphrase \[dq]$PASSWORD\[dq] \[rs]
--output \[dq]$OUTPUT\[dq] \[rs] --output \[dq]$OUTPUT\[dq] \[rs]
\[dq]$INPUT\[dq] \[dq]$INPUT\[dq]
.EE \f[R]
.fi
.PP .PP
This command encrypts the backup using the AES-256 symmetric encryption This command encrypts the backup using the AES-256 symmetric encryption
algorithm with a 256bit key. algorithm with a 256bit key.
Here is what each flag do: - \f[CR]--symmetric\f[R]: Use symmetric Here is what each flag do: - \f[V]--symmetric\f[R]: Use symmetric
encryption; encryption;
.PD 0 .PD 0
.P .P
.PD .PD
- \f[CR]--cipher-algo=AES256\f[R]: Use AES256 algorithm; - \f[V]--cipher-algo=AES256\f[R]: Use AES256 algorithm;
.PD 0 .PD 0
.P .P
.PD .PD
- \f[CR]--no-symkey-cache\f[R]: Do not save password on GPG\[cq]s cache; - \f[V]--no-symkey-cache\f[R]: Do not save password on GPG\[cq]s cache;
.PD 0 .PD 0
.P .P
.PD .PD
- \f[CR]--pinentry-mode=loopback --batch\f[R]: Do not prompt the user; - \f[V]--pinentry-mode=loopback --batch\f[R]: Do not prompt the user;
.PD 0 .PD 0
.P .P
.PD .PD
- \f[CR]--passphrase-fd 3 3<< \[dq]$PASSWORD\[dq]\f[R]: Read password - \f[V]--passphrase-fd 3 3<< \[dq]$PASSWORD\[dq]\f[R]: Read password
without revealing it on \f[CR]ps\f[R]; without revealing it on \f[V]ps\f[R];
.PD 0 .PD 0
.P .P
.PD .PD
- \f[CR]--output\f[R]: Specify output file; - \f[V]--output\f[R]: Specify output file;
.PD 0 .PD 0
.P .P
.PD .PD
- \f[CR]$INPUT\f[R]: Specify input file. - \f[V]$INPUT\f[R]: Specify input file.
.SS Plausible Deniability
.PP
While \f[V]backup.sh\f[R] provide some pretty strong security against
bruteforce attack(assuming a strong passphrase is being used) it should
by no means considered a viable tool against a cryptanalysis
investigation.
Many of the copying, compressing and encrypting operations made by
\f[V]backup.sh\f[R] during the backup process can be used to invalidate
plausible deniability.
In particular, you should pay attention to the following details:
.IP "1." 3
The \f[V]--checksum\f[R] option generates an \f[B]UNENCRYPTED\f[R]
checksum file containing the \f[I]digests\f[R] of \f[B]EVERY\f[R] file
in your backup archive.
If your files are known to your adversary(e.g., a banned book), they may
use a rainbow table attack to determine whether you own a given file,
voiding your plausible deniability;
.PD 0
.P
.PD
.IP "2." 3
Since \f[V]backup.sh\f[R] is essentially a set of shell commands, an
eavesdropper could monitor the whole backup process to extract the name
of the files or the encryption password.
.SH EXAMPLES .SH EXAMPLES
.PP
Below there are some examples that demonstrate \f[B]backup.sh\f[R]\[cq]s Below there are some examples that demonstrate \f[B]backup.sh\f[R]\[cq]s
usage. usage.
.IP "1." 3 .IP "1." 3
Create a backup of \f[CR]/etc/ssh\f[R], \f[CR]/var/www\f[R] and Create a backup of \f[V]/etc/ssh\f[R], \f[V]/var/www\f[R] and
\f[CR]/var/log\f[R] inside the \f[CR]/tmp\f[R] directory using a \f[V]/var/log\f[R] inside the \f[V]/tmp\f[R] directory using a password
password stored in \f[CR]/home/op1/.backup_pw\f[R] stored in \f[V]/home/op1/.backup_pw\f[R]
.PP .PP
The first thing to do is to define the source paths inside a The first thing to do is to define the source paths inside a
\f[I]sources file\f[R]: \f[I]sources file\f[R]:
.IP .IP
.EX .nf
\f[C]
$> cat sources.bk $> cat sources.bk
ssh=/etc/ssh ssh=/etc/ssh
web_root=/var/www web_root=/var/www
logs=/var/log logs=/var/log
.EE \f[R]
.fi
.PP .PP
After that we can load our encryption key from the specified file inside After that we can load our encryption key from the specified file inside
a environment variable: an environment variable:
.IP .IP
.EX .nf
\f[C]
$> ENC_KEY=$(cat /home/op1/.backup_pw) $> ENC_KEY=$(cat /home/op1/.backup_pw)
.EE \f[R]
.fi
.PP .PP
Finally, we can start the backup process with: Finally, we can start the backup process with:
.IP .IP
.EX .nf
\f[C]
$> sudo backup.sh --backup sources.bk /tmp $ENC_KEY $> sudo backup.sh --backup sources.bk /tmp $ENC_KEY
.EE \f[R]
.fi
.IP "2." 3 .IP "2." 3
Extract the content of a backup made on 2023-03-14 with the password Extract the content of a backup made on 2023-03-14 with the password
`Ax98f!' `Ax98f!'
.PP .PP
To do this, we can simply issue the following command: To do this, we can simply issue the following command:
.IP .IP
.EX .nf
\f[C]
$> backup.sh --extract backup-af9a8e6bfe15-20230314.tar.gz.enc \[dq]Ax98f!\[dq] $> backup.sh --extract backup-af9a8e6bfe15-20230314.tar.gz.enc \[dq]Ax98f!\[dq]
.EE \f[R]
.fi
.IP "3." 3 .IP "3." 3
Extract the content of a backup made on 2018-04-25 using the password in Extract the content of a backup made on 2018-04-25 using the password in
\f[CR]/home/john/.pw\f[R] \f[V]/home/john/.pw\f[R]
.PP .PP
This example is very similar to the previous one, we just need to read This example is very similar to the previous one, we just need to read
the password from the text file: the password from the text file:
.IP .IP
.EX .nf
\f[C]
$> backup.sh --extract backup-af9a8e6bfe15-20180425.tar.gz.enc \[dq]$(cat /home/john/.pw)\[dq] $> backup.sh --extract backup-af9a8e6bfe15-20180425.tar.gz.enc \[dq]$(cat /home/john/.pw)\[dq]
.EE \f[R]
.fi
.SH AUTHORS .SH AUTHORS
.PP
\f[B]backup.sh\f[R] was written by Marco Cetica on late 2018. \f[B]backup.sh\f[R] was written by Marco Cetica on late 2018.
.SH BUGS .SH BUGS
.PP
Submit bug reports online at: <email@marcocetica.com> or open an issue Submit bug reports online at: <email@marcocetica.com> or open an issue
on the issue tracker of the GitHub page of this project: on the issue tracker of the GitHub page of this project:
https://github.com/ice-bit/backup.sh https://github.com/ice-bit/backup.sh

126
man.md
View File

@ -3,7 +3,7 @@ title: backup.sh
section: 1 section: 1
header: General Commands Manual header: General Commands Manual
footer: Marco Cetica footer: Marco Cetica
date: February 27, 2024 date: April 3, 2024
--- ---
# NAME # NAME
@ -11,102 +11,107 @@ date: February 27, 2024
# SYNOPSIS # SYNOPSIS
``` ```
Syntax: backup.sh [-b|-e|-h] Syntax: ./backup.sh [-b|-c|-e|-h]
options: options:
-b|--backup SOURCES DEST PASS Backup folders from SOURCES file. -b|--backup SOURCES DEST PASS Backup folders from SOURCES file.
-e|--extract ARCHIVE PASS Extract ARCHIVE using PASS. -c|--checksum Generate/check SHA256 of a backup.
-h|--help Show this helper. -e|--extract ARCHIVE PASS Extract ARCHIVE using PASS.
-h|--help Show this helper.
``` ```
# DESCRIPTION # DESCRIPTION
**backup.sh** is a POSIX compliant, modular and lightweight backup utility to save and encrypt your files. **backup.sh** is a POSIX compliant, modular and lightweight backup utility to save and encrypt your files.
This tool is intended to be used on small scale UNIX environment such as VPS, small servers and workstations. This tool is intended to be used on small scale UNIX environment such as VPS, small servers and workstations.
**backup.sh** uses _rsync_, _tar_ and _gpg_ to copy, compress and encrypt the backup. **backup.sh** uses _rsync_, _tar_, _sha256sum_ and _gpg_ to copy, compress, verify and encrypt the backup.
# OPTIONS # OPTIONS
**backup.sh** supports two options: _backup creation_ and _backup extraction_. **backup.sh** supports three options: **backup creation**, **backup extraction** and **checksum** to verify the
The former requires root permissions, while the latter does not. Let us see them in details: integrity of a backup. The first option requires
root permissions, while the second one does not. The checksum option must be used in combination of one of the previous options.
## Backup creation ## Backup creation
To specify the directories to backup, **backup.sh** uses an associative array defined in a text file(called sources file) To specify the directories to back up, `backup.sh` uses an associative array
with the following syntax: defined in a text file(called _sources file_) with the following syntax:
``` ```
<LABEL>=<PATH> <LABEL>=<PATH>
``` ```
Where `<LABEL>` is the name of the backup and `<PATH>` is its path. Where `<LABEL>` is the name of the backup and `<PATH>` is its path. For example,
For example, if you want to back up _/etc/nginx_ and _/etc/ssh_, add the following entries to the sources file: if you want to back up `/etc/nginx` and `/etc/ssh`, add the following entries to the _sources file_:
``` ```
nginx=/etc/nginx/ nginx=/etc/nginx/
ssh=/etc/ssh/ ssh=/etc/ssh/
``` ```
**backup.sh** will create two folders inside the backup archive with the following syntax: `backup.sh` will create two folders inside the backup archive with the following syntax:
``` ```
backup-<LABEL>-<YYYYMMDD> backup-<LABEL>-<YYYYMMDD>
``` ```
In the previous example, this would be: In the previous example, this would be:
``` ```
backup-nginx-<YYYYMMDD> backup-nginx-<YYYYMMDD>
backup-ssh-<YYYYMMDD> backup-ssh-<YYYYMMDD>
``` ```
You can add as many entries as you want, just be sure to use the proper syntax. You can add as many entries as you want, just be sure to use the proper syntax. In particular,
In particular, the sources file, _should not_ includes: the _sources file_, **should not** include:
- Spaces between the label and the equal sign;
- Empty lines;
- Comments.
- Spaces between the label and the equal sign; You can find a sample _sources file_ at `sources.bk`(or at `/usr/local/etc/sources.bk`).
- Empty lines;
- Comments.
You can find a sample sources file at `sources.bk`(or at `/usr/local/etc/sources.bk`). After having defined the _sources file_, you can invoke `backup.sh` using the following syntax:
After having defined the sources file, you can invoke **backup.sh** using the following syntax:
``` ```
$> sudo ./backup.sh --backup <SOURCES_FILE> <DEST> <ENCRYPTION_PASSWORD> $> sudo ./backup.sh --backup <SOURCES_FILE> <DEST> <ENCRYPTION_PASSWORD>
``` ```
Where `<SOURCES_FILE>` is the _sources file_, `<DEST>` is the absolute path of the output of the backup _without trailing slashes_ Where `<SOURCES_FILE>` is the _sources file_, `<DEST>` is the absolute path of the output of the backup
and `<ENCRYPTION_PASSWORD>` is the password to encrypt the compressed archive. **without trailing slashes** and `<ENCRYPTION_PASSWORD>` is the password to encrypt the compressed archive.
In the previous example, this would be: In the previous example, this would be:
``` ```
$> sudo ./backup.sh --backup sources.bk /home/john badpw1234 $> sudo ./backup.sh --backup sources.bk /home/john badpw1234
``` ```
The backup utility will begin to copy the files defined in the sources file: You can also tell `backup.sh` to generate a SHA256 file containing the hash of each file using the `-c` option.
In the previous example, this would be:
```
$> sudo ./backup.sh --checksum --backup sources.bk /home/john badpw1234
```
The backup utility will begin to copy the files defined in the _sources file_:
``` ```
Copying nginx(1/2) Copying nginx(1/2)
Copying ssh(2/2) Copying ssh(2/2)
Compressing backup... Compressing backup...
Encrypting backup... Encrypting backup...
File name: /home/marco/backup-<HOSTNAME>-<YYYYMMDD>.tar.gz.enc File name: /home/john/backup-<HOSTNAME>-<YYYYMMDD>.tar.gz.enc
Checksum file: /home/john/backup-<HOSTNAME>-<YYYYMMDD>.sha256
File size: 7336400696(6.9G) File size: 7336400696(6.9G)
File hash: 0e75ca393117f389d9e8edfea7106d98
Elapsed time: 259 seconds. Elapsed time: 259 seconds.
``` ```
After that, you will find the final backup archive in `/home/john/backup-<HOSTNAME>-<YYYYMMDD>.tar.gz.enc`. After that, you will find the backup archive and the checksum file in
`/home/john/backup-<HOSTNAME>-<YYYYMMDD>.tar.gz.enc` and `/home/john/backup-<HOSTNAME>-<YYYYMMDD>.sha256`, respectively.
You can also use **backup.sh** from a crontab rule:
You can also use `backup.sh` from a crontab rule:
``` ```
$> sudo crontab -e $> sudo crontab -e
30 03 * * 6 EKEY=$(cat /home/john/.ekey) sh -c '/usr/local/bin/backup.sh -b /usr/local/etc/sources.bk /home/john $EKEY' > /dev/null 2>&1 30 03 * * 6 EKEY=$(cat /home/john/.ekey) sh -c '/usr/local/bin/backup.sh -b /usr/local/etc/sources.bk /home/john $EKEY' > /dev/null 2>&1
``` ```
This will automatically run **backup.sh** every Saturday morning at 03:30 AM. This will automatically run `backup.sh` every Saturday morning at 03:30 AM. In the example above, the encryption
In the example above, the encryption key is stored in a local file(with fixed permissions) to avoid password leaking in crontab logs. key is stored in a local file(with fixed permissions) to avoid password leaking in crontab logs. You can also
You can also adopt this practice while using the `--extract` option to avoid password leaking in shell history. adopt this practice while using the `--extract` option to avoid password leaking in shell history.
## Backup extraction ## Backup extraction
**backup.sh** can also extract the encrypted backup archive using the following syntax: **backup.sh** can also be used to extract the encrypted backup as well to verify the integrity
of the backup data. To do so, use the following commands:
``` ```
$> ./backup.sh --extract <ENCRYPTED_ARCHIVE> <ARCHIVE_PASSWORD> $> ./backup.sh --extract <ENCRYPTED_ARCHIVE> <ARCHIVE_PASSWORD>
@ -115,20 +120,36 @@ $> ./backup.sh --extract <ENCRYPTED_ARCHIVE> <ARCHIVE_PASSWORD>
Where `<ENCRYPTED_ARCHIVE>` is the encrypted backup and `<ARCHIVE_PASSWORD>` is the backup password. Where `<ENCRYPTED_ARCHIVE>` is the encrypted backup and `<ARCHIVE_PASSWORD>` is the backup password.
For instance: For instance:
``` ```
$> ./backup.sh --extract backup-<hostname>-<YYYYMMDD>.tar.gz.enc badpw1234 $> ./backup.sh --extract backup-<hostname>-<YYYYMMDD>.tar.gz.enc badpw1234
``` ```
This will create a new folder called `backup.sh.tmp` in your local directory. This will create a new folder called `backup.sh.tmp` in your local directory with the following content:
Be sure to rename any directory with that name to avoid collisions. From the previous example, you should have the following directories:
``` ```
backup-nginx-<YYYYMMDD> backup-nginx-<YYYYMMDD>
backup-ssh-<YYYYMMDD> backup-ssh-<YYYYMMDD>
``` ```
**note:**: be sure to rename any directory with that name to avoid collisions.
Instead, if you also want to verify the integrity of the backup data, use the following commands:
```
$> ./backup.sh --checksum --extract <ENCRYPTED_ARCHIVE> <ARCHIVE_PASSWORD> <CHECKSUM_ABSOLUTE_PATH>
```
For instance:
```
$> ./backup.sh --checksum --extract backup-<hostname>-<YYYYMMDD>.tar.gz.enc badpw1234 $PWD/backup-<hostname>-<YYYYMMDD>.sha256
```
**note:** be sure to provide the ABSOLUTE PATH of the checksum file.
## How does backup.sh work? ## How does backup.sh work?
**backup.sh** uses _rsync_ to copy the files, _tar_ to compress the backup and _gpg_ to encrypt it. **backup.sh** uses _rsync_ to copy the files, _tar_ to compress the backup, _gpg_ to encrypt it and
_sha256sum_ to verify it.
By default, rsync is being used with the following parameters: By default, rsync is being used with the following parameters:
``` ```
@ -144,17 +165,22 @@ That is:
- q: quiet mode: reduces the amount of information rsync produces; - q: quiet mode: reduces the amount of information rsync produces;
- delete: delete mode: forces rsync to delete any extraneous files at the destination dir. - delete: delete mode: forces rsync to delete any extraneous files at the destination dir.
If specified(`--checksum` option), `backup.sh` can also generate the checksum of each file of the backup.
To do so, it uses `sha256sum(1)` to compute the hash of every single file using the SHA256 hashing algorithm.
The checksum file contains nothing but the checksums of the files, no other information about the files stored
on the backup archive is exposed on the unencrypted checksum file. This may be an issue if you want plausible
deniability(see privacy section for more information).
After that the backup folder is being encrypted using gpg. By default, it is used with the following parameters: After that the backup folder is being encrypted using gpg. By default, it is used with the following parameters:
``` ```
$> gpg -a \ $> gpg -a \
--symmetric \ --symmetric \
--cipher-algo=AES256 \ --cipher-algo=AES256 \
--no-symkey-cache \ --no-symkey-cache \
--pinentry-mode=loopback \ --pinentry-mode=loopback \
--batch --passphrase-fd "$PASSWORD" \ --batch --passphrase "$PASSWORD" \
--output "$OUTPUT" \ --output "$OUTPUT" \
"$INPUT" "$INPUT"
``` ```
@ -168,6 +194,19 @@ This command encrypts the backup using the AES-256 symmetric encryption algorith
- `--output`: Specify output file; - `--output`: Specify output file;
- `$INPUT`: Specify input file. - `$INPUT`: Specify input file.
## Plausible Deniability
While `backup.sh` provide some pretty strong security against bruteforce attack(assuming a strong passphrase is being used)
it should by no means considered a viable tool against a cryptanalysis investigation. Many of the copying, compressing and
encrypting operations made by `backup.sh` during the backup process can be used to invalidate plausible deniability.
In particular, you should pay attention to the following details:
1. The `--checksum` option generates an **UNENCRYPTED** checksum file containing the _digests_ of **EVERY**
file in your backup archive. If your files are known to your adversary(e.g., a banned book), they may use a rainbow table attack to
determine whether you own a given file, voiding your plausible deniability;
2. Since `backup.sh` is essentially a set of shell commands, an eavesdropper could monitor the whole backup process to extract
the name of the files or the encryption password.
# EXAMPLES # EXAMPLES
Below there are some examples that demonstrate **backup.sh**'s usage. Below there are some examples that demonstrate **backup.sh**'s usage.
@ -183,7 +222,7 @@ web_root=/var/www
logs=/var/log logs=/var/log
``` ```
After that we can load our encryption key from the specified file inside a environment variable: After that we can load our encryption key from the specified file inside an environment variable:
``` ```
$> ENC_KEY=$(cat /home/op1/.backup_pw) $> ENC_KEY=$(cat /home/op1/.backup_pw)
@ -196,7 +235,6 @@ $> sudo backup.sh --backup sources.bk /tmp $ENC_KEY
``` ```
2. Extract the content of a backup made on 2023-03-14 with the password 'Ax98f!' 2. Extract the content of a backup made on 2023-03-14 with the password 'Ax98f!'
To do this, we can simply issue the following command: To do this, we can simply issue the following command:

View File

@ -5,6 +5,8 @@
# By Marco Cetica 2023 (<email@marcocetica.com>) # By Marco Cetica 2023 (<email@marcocetica.com>)
# #
set -e
helper() { helper() {
cat <<EOF cat <<EOF
backup.sh unit testing suite. backup.sh unit testing suite.
@ -49,11 +51,13 @@ create_files() {
} }
execute_backup() { execute_backup() {
./backup.sh -b sources.bk "$PWD" badpw ./backup.sh -c -b sources.bk "$PWD" badpw
} }
extract_backup() { extract_backup() {
./backup.sh -e "$PWD"/backup-*-*.tar.gz.enc badpw host="$(uname -n)"
date="$(date +'%Y%m%d')"
./backup.sh -c -e "$PWD"/backup-"$host"-"$date".tar.gz.enc badpw "$PWD"/backup-"$host"-"$date".sha256
} }
test_backup() { test_backup() {