Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
cryptsync - rsync a folder to an encrypted disk image
#!/bin/bash
# cryptsync.sh - a simple script for keeping an encrypted backup of a folder
#
# Author: Rasmus Sten <cryptsync@dll.nu>
#
# For example, to make an encrypted backup of my ~/Documents folder to Dropbox:
#
# ./cryptsync.sh --init ~/Documents/ ~/Dropbox/
#
# Later, to update the backup, re-run th script without the --init option:
#
# ./cryptsync.sh ~/Documents/ ~/Dropbox/
#
# The target path can be any directory or mount point, e.g. a USB flash drive,
# an NFS share or web service such as iDisk or DropBox.
#
# To examine the contents of the disk image, you can use the --leave-mounted
# option to prevent the script from unmounting it after synchronization.
#
# On Linux, the script requires cryptsetup and sudo privilege is required to
# setup the loopback interfaces and mount the LUKS image.
# On Mac, it should work on a base Mac OS X system with standard user
# privileges.
#
# Run the script without any parameters for more usage information.
#
# The script works on Linux and Mac OS X, but the disk images created on Linux
# cannot be used in Mac OS X and vice versa. On Linux, an ext3-formatted LUKS
# image called "encrypted.luks" is created, while on Mac it is a sparse native
# HFS+ disk image called "encrypted.sparseimage". The default size is 1 GB.
#
exiterror() {
echo "$*" >&2
exit 1
}
usage() {
echo "Usage:"
echo -e "\t$0 [--leave-mounted] [--init] <src-dir> <dst-dir>"
echo
echo " --leave-mounted don't unmount after synchronizing"
echo " --init create and format an encyptred disk image first"
echo
echo "Note: the order of options matters"
echo
echo "Examples:"
echo -e "\t$0 --init ~/Documents /mnt/usbdrive"
echo -e "\t\tWill create an encrypted disk image in /mnt/usbdrive with the"
echo -e "\t\tdirectory ~/Documents (and its contents) in its root folder"
echo
echo -e "\t$0 ~/important /Volumes/Thumbdrive"
echo -e "\t\tLocate an encrypted disk image in /Volumes/Thumbdrive and"
echo -e "\t\tsynchronize the directory ~/important onto it"
echo
exit 1
}
mounted=false
found=false
lookedfor=""
tmpfile=`mktemp -t cryptsync.XXXXXX`
gigs=1
leavemounted=false
if [ "$1" = "--leave-mounted" ] ; then
shift
leavemounted=true
fi
[ "$1" -a "$2" ] || usage
if [ "$1" = "--init" ] ; then
shift
src="$1"
dst="$2"
if [ `uname` = "Darwin" ] ; then
imgfile="${dst}/encrypted.sparseimage"
if [ -e "$imgfile" ] ; then
exiterror "$imgfile already exists"
fi
echo "Creating a sparse encrypted disk image in file $imgfile"
hdiutil create -attach -encryption AES-256 -type SPARSE -fsargs "-v cryptsync" -fs HFS+J -size ${gigs}g "$imgfile" > $tmpfile || exiterror "Failed to create the disk image"
# save mount point information for later
mv $tmpfile ${tmpfile}.tmp
grep -v ^created ${tmpfile}.tmp > $tmpfile
mounted=true
found=true
elif [ `uname` = "Linux" ] ; then
imgfile="${dst}/encrypted.luks"
if [ -f "$imgfile" ] ; then
exiterror "Cowardly refusing to overwrite $imgfile"
fi
echo "Creating $imgfile"
dd if=/dev/zero of="$imgfile" bs=$((1024*1024)) count=$(($gigs * 1024))
dev=`sudo losetup -f`
sudo losetup $dev $imgfile || exiterror "Failed to setup loop device $dev for $imgfile"
sudo cryptsetup luksFormat -q $dev
mapname=cryptsync.$$
sudo cryptsetup luksOpen $dev $mapname || exiterror "Failed to luksOpen $dev $mapname"
sudo mkfs.ext3 /dev/mapper/$mapname || exiterror "Failed to create a filesystem on $mapname"
mountpoint=`sudo mktemp -d /mnt/cryptsync.XXXXXX`
sudo mount /dev/mapper/$mapname $mountpoint || exiterror "failed to mount $dev on $mountpoint"
mounted=true
found=true
else
echo "This part not done for `uname` yet."
fi
else
src="$1"
dst="$2"
fi
# strip trailing slash
src=`echo "$src" | sed -e 's/\/$//'`
if ! $mounted ; then
if [ `uname` = "Darwin" ] ; then
for ext in dmg sparseimage ; do
f="$dst"/encrypted.$ext
lookedfor="$lookedfor $f"
if [ -e $f ] ; then
found=true
hdiutil attach $f > $tmpfile && mounted=true
break
fi
done
elif [ `uname` = "Linux" ] ; then
f="$dst"/encrypted.luks
lookedfor="$f"
if [ -f "$f" ] ; then
found=true
dev=`sudo losetup -f`
[ -z "$dev" ] && exiterror "Failed to acquire loopback device"
sudo losetup $dev $f
mapname=cryptsync.$$
sudo cryptsetup luksOpen $dev $mapname
mountpoint=`sudo mktemp -d /mnt/cryptsync.XXXXXX`
sudo mount /dev/mapper/$mapname $mountpoint || exiterror "failed to mount $dev on $mountpoint"
mounted=true
fi
else
echo Unsupported OS: `uname`
exit 1
fi
fi
if ! $found ; then
exiterror "Couldn't find any encrypted disk image. Looked for: $lookedfor"
fi
if ! $mounted ; then
echo Nothing mounted.
exit 1
fi
if [ -z "$mountpoint" ] ; then
mountpoint=`tail -1 $tmpfile | awk 'BEGIN { FS = "\t" } { print $3 }'`
fi
if [ ! -d "$mountpoint" ] ; then
echo "Can't find supposed mount point $mountpoint"
exit 1
fi
if [ `uname` = "Linux" ] ; then
sudo chown $USER $mountpoint
fi
echo "Synchronizing $src to $mountpoint"
rsync -az "$src" "$mountpoint"
if ! $leavemounted ; then
if [ `uname` = "Darwin" ] ; then
hdiutil detach "$mountpoint"
elif [ `uname` = "Linux" ] ; then
echo -n Cleaning up...
sudo umount $mountpoint || exiterror "Unmount of $mountpoint failed"
sudo rmdir $mountpoint || exiterror "Failed to remove mount point $mountpoint"
sudo cryptsetup luksClose /dev/mapper/$mapname || exiterror "Failed to luksClose"
sudo losetup -d $dev || exiterror "Failed to delete loop"
echo " OK."
else
echo "Don't know how to deal with `uname`"
fi
else
echo "Mounted on $mountpoint"
if [ `uname` = "Darwin" ] ; then
open "$mountpoint"
fi
fi
exit 0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.