mirror of
https://github.com/prurigro/cryptobox.git
synced 2024-12-29 02:44:34 -05:00
Rewrite the script using best practices, way more error checks, nice colour output and an updated encryption algorithm for new images
This commit is contained in:
parent
f32decc0da
commit
4376e91b94
2 changed files with 262 additions and 80 deletions
28
README.md
28
README.md
|
@ -1,25 +1,29 @@
|
|||
# Cryptobox #
|
||||
# Cryptobox
|
||||
|
||||
A wrapper script for **cryptsetup** that makes it easy to create, mount and unmount encrypted image files using LUKS.
|
||||
A script that makes it easy to create, mount and unmount encrypted images in Linux using LUKS
|
||||
|
||||
## Requirements ##
|
||||
|
||||
* **cryptsetup**: Userspace setup tool for transparent encryption of block devices using.
|
||||
* **util-linux**: Miscellaneous system utilities for Linux, required for **losetup** and **mkfs**.
|
||||
* **cryptsetup**
|
||||
* **util-linux**:
|
||||
* **losetup**
|
||||
* **mkfs**
|
||||
* **coreutils**:
|
||||
* **dd**
|
||||
|
||||
## Usage ##
|
||||
|
||||
* `cryptobox`: displays the list of commands
|
||||
* `cryptobox c filename.img filesystem size-in-mb`: creates an image file with a given filesystem and size in megabytes.
|
||||
* eg: `cryptobox c myimg.img ext4 128`
|
||||
* `cryptobox m filename.img /mount/point`: mounts a given image file on a given directory.
|
||||
* eg: `cryptobox m myimg.img /mnt/cryptoimg`
|
||||
* `cryptobox u /mount/point`: unmounts an image file from a given directory.
|
||||
* eg: `cryptobox u /mnt/cryptoimg`
|
||||
* **create**: `c|-c|--create [filename] [filesystem] [size-in-mb]`
|
||||
* **mount**: `m|-m|--mount [filename] [mountpoint]`
|
||||
* **umount**: `u|-u|--unmount [mountpoint]`
|
||||
* **help**: `h|-h|--help`
|
||||
|
||||
## Credits ##
|
||||
|
||||
Written by Kevin MacMartin: [GitHub Projects](https://github.com/prurigro?tab=repositories) | [Arch Linux AUR Packages](https://aur.archlinux.org/packages/?SeB=m&K=prurigro)
|
||||
Written by Kevin MacMartin
|
||||
|
||||
* [GitHub Projects](https://github.com/prurigro?tab=repositories)
|
||||
* [Arch Linux AUR Packages](https://aur.archlinux.org/packages/?SeB=m&K=prurigro)
|
||||
|
||||
## License ##
|
||||
|
||||
|
|
314
cryptobox
314
cryptobox
|
@ -1,87 +1,265 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
##############################################################
|
||||
# #
|
||||
# CryptoBox #
|
||||
# #
|
||||
# A script that wraps cryptsetup, mkfs and losetup to make #
|
||||
# it easy to create, mount and unmount encrypted image #
|
||||
# files using LUKS. #
|
||||
# #
|
||||
##############################################################
|
||||
#
|
||||
# CryptoBox
|
||||
#
|
||||
# A script that makes it easy to create, mount
|
||||
# and unmount encrypted images in Linux using LUKS
|
||||
#
|
||||
# Written by Kevin MacMartin
|
||||
#
|
||||
# Licensed under the GPLv3
|
||||
#
|
||||
|
||||
NAME=`echo "$0" | grep -o -e "[^\/]*$"`
|
||||
[[ -t 1 ]] && {
|
||||
c_d=$'\e[1;30m' # DARK GREY
|
||||
c_r=$'\e[1;31m' # RED
|
||||
c_g=$'\e[1;32m' # GREEN
|
||||
c_y=$'\e[1;33m' # YELLOW
|
||||
c_b=$'\e[1;34m' # BLUE
|
||||
c_m=$'\e[1;35m' # VIOLET
|
||||
c_t=$'\e[1;36m' # TEAL
|
||||
c_w=$'\e[1;37m' # WHITE
|
||||
c_u=$'\e[1;4;37m' # UNDERLINE WHITE
|
||||
c_h=$'\e[1;41m' # HIGHLIGHT RED
|
||||
c_c=$'\e[0m' # DISABLES COLOUR
|
||||
}
|
||||
|
||||
function errorquit {
|
||||
echo -e "Error: $1"
|
||||
[[ "$1" = "syntax" ]] && (echo; usage)
|
||||
# The name of the script
|
||||
scriptname="${0/*\/}"
|
||||
|
||||
# Display uage information
|
||||
function usage {
|
||||
printf '%s\n\n' "${c_w}Create, mount and unmount encrypted images${c_c}"
|
||||
printf '%s\n' "${c_w}Usage:${c_c}"
|
||||
printf ' %s\n' "${c_y}create${c_w}: ${c_m}c${c_w}|${c_m}-c${c_w}|${c_m}--create${c_c} ${c_w}$scriptname${c_c} ${c_m}c${c_c} [${c_b}filename${c_c}] [${c_g}filesystem${c_c}] [${c_t}size-in-mb${c_c}]"
|
||||
printf ' %s\n' "${c_y}mount${c_w}: ${c_m}m${c_w}|${c_m}-m${c_w}|${c_m}--mount${c_c} ${c_w}$scriptname${c_c} ${c_m}m${c_c} [${c_b}filename${c_c}] [${c_r}mountpoint${c_c}]"
|
||||
printf ' %s\n' "${c_y}umount${c_w}: ${c_m}u${c_w}|${c_m}-u${c_w}|${c_m}--unmount${c_c} ${c_w}$scriptname${c_c} ${c_m}u${c_c} [${c_r}mountpoint${c_c}]"
|
||||
printf ' %s\n' "${c_y}help${c_w}: ${c_m}h${c_w}|${c_m}-h${c_w}|${c_m}--help${c_c} ${c_w}$scriptname${c_c} ${c_m}h${c_c}"
|
||||
exit "$1"
|
||||
}
|
||||
|
||||
# Exit with a nicely formatted error
|
||||
function error_exit {
|
||||
printf '%s\n' "${c_r}Error${c_c}: ${c_w}$1${c_c}" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
function usage {
|
||||
echo -e "${NAME}: create and mount encrypted images\n"
|
||||
echo "Usage: $NAME option arguments"
|
||||
echo -e "\tc (create) -> $NAME c filename.img filesystem size-in-mb"
|
||||
echo -e "\tm (mount) -> $NAME m filename.img /mount/point"
|
||||
echo -e "\tu (umount) -> $NAME u /mount/point"
|
||||
function luks_open {
|
||||
loopdev="$1"
|
||||
container="$2"
|
||||
|
||||
# Decrypt the image so we can use it
|
||||
while (( 1 )); do
|
||||
if cryptsetup luksOpen "$loopdev" "$container"; then
|
||||
break
|
||||
else
|
||||
printf '%s' "${c_w}Failed to decrypt ${c_m}$container${c_w}, press return to try again or ctrl+c to exit$c_c"
|
||||
read -r
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
function luks_close {
|
||||
loopdev="$1"
|
||||
container="$2"
|
||||
|
||||
# Close the encrypted device
|
||||
cryptsetup luksClose "$container" || error_exit "Unable to close the decrypted device for ${c_m}$container"
|
||||
sleep 1
|
||||
|
||||
# Close the loop device
|
||||
losetup -d "$loopdev" || error_exit "Unable to close the loop device ${c_m}$loopdev"
|
||||
}
|
||||
|
||||
function create_image {
|
||||
# Exit with an error if exactly 3 arguments haven't been given
|
||||
[[ -n "$3" && -z "$4" ]] || error_exit 'Incorrect number of arguments for the create command'
|
||||
|
||||
# Store the provided arguments as named variables so they're easier to keep track of
|
||||
filename="$1"
|
||||
filesystem="$2"
|
||||
size="$3"
|
||||
|
||||
# Exit with an error if the image file already exists
|
||||
[[ ! -e "$filename" ]] || error_exit "$filename already exists"
|
||||
|
||||
# Exit with an error if the filesystem isn't available
|
||||
mkfs_binaries=("$(type -P mkfs)".*)
|
||||
grep -q mkfs."$filesystem" <<< "${mkfs_binaries[*]}" || error_exit "The filesystem ${c_m}$filesystem${c_w} is not available"
|
||||
|
||||
# Exit with an error if size isn't a number
|
||||
[[ "$size" =~ ^[0-9]*$ ]] || error_exit 'The argument for the size is not a number'
|
||||
|
||||
# Exit with an error if size is less than 18
|
||||
(( size >= 18 )) || error_exit 'The size of the image must be 18 megabytes or larger'
|
||||
|
||||
# Retrieve the first unused loop device name
|
||||
loopdev=$(losetup -f)
|
||||
|
||||
# Retrieve an appropriate name for the container
|
||||
container="${loopdev/*\/}"
|
||||
|
||||
# Exit with an error if a container already exists with this name
|
||||
[[ ! -e "/dev/mapper/$container" ]] || error_exit "A container already exists at ${c_m}/dev/mapper/$container"
|
||||
|
||||
# Create the image file at the requested size and filled with random data
|
||||
dd bs=1M count="$size" if=/dev/urandom of="$filename" || error_exit "Unable to create ${c_m}$filename"
|
||||
|
||||
# Setup the loop device
|
||||
losetup "$loopdev" "$filename" || error_exit "Unable to connect ${c_m}$filename${c_w} to the loop device ${c_m}$loopdev"
|
||||
|
||||
# Initialize encryption on the image
|
||||
while (( 1 )); do
|
||||
if cryptsetup -c aes-xts-plain64 -y -s 512 luksFormat "$loopdev"; then
|
||||
break
|
||||
else
|
||||
printf '%s' "${c_w}Failed to encrypt the image, press return to try again or ctrl+c to exit$c_c"
|
||||
read -r
|
||||
fi
|
||||
done
|
||||
|
||||
# Decrypt the image so we can use it
|
||||
luks_open "$loopdev" "$container"
|
||||
|
||||
# Initialize the target filesystem on the device
|
||||
mkfs -t "$filesystem" "/dev/mapper/${container}" || error_exit "Unable to create the ${c_m}$filesystem${c_w} filesystem"
|
||||
sync
|
||||
|
||||
# Close the decrypted image
|
||||
luks_close "$loopdev" "$container"
|
||||
}
|
||||
|
||||
function mount_image {
|
||||
# Exit with an error if exactly 3 arguments haven't been given
|
||||
[[ -n "$2" && -z "$3" ]] || error_exit 'Incorrect number of arguments for the create command'
|
||||
|
||||
# Store the provided arguments as named variables so they're easier to keep track of
|
||||
filename="$1"
|
||||
mountpoint="$2"
|
||||
|
||||
# Exit with an error if either the image file or mount point do not exist
|
||||
[[ ! -f "$filename" ]] && error_exit "${c_m}$filename${c_w} does not exist"
|
||||
[[ -e "$mountpoint" ]] || error_exit "${c_m}$mountpoint${c_w} does not exist"
|
||||
[[ -d "$mountpoint" ]] || error_exit "${c_m}$mountpoint${c_w} is not a directory"
|
||||
|
||||
# Retrieve the first unused loop device name
|
||||
loopdev=$(losetup -f)
|
||||
|
||||
# Retrieve an appropriate name for the container
|
||||
container="${loopdev/*\/}"
|
||||
|
||||
# Exit with an error if a container already exists with this name
|
||||
[[ ! -e "/dev/mapper/$container" ]] || error_exit "A container already exists at ${c_m}/dev/mapper/$container"
|
||||
|
||||
# Setup the loop device
|
||||
losetup "$loopdev" "$filename" || error_exit "Unable to connect ${c_m}$filename${c_w} to the loop device ${c_m}$loopdev${c_w}"
|
||||
|
||||
# Decrypt the image so we can use it
|
||||
luks_open "$loopdev" "$container"
|
||||
|
||||
# Mount the mapped decrypted image
|
||||
mount "/dev/mapper/$container" "$mountpoint" || error_exit "Unable to mount ${c_m}/dev/mapper/${container}${c_w} on ${c_m}$mountpoint"
|
||||
}
|
||||
|
||||
function unmount_image {
|
||||
# Exit with an error if exactly 3 arguments haven't been given
|
||||
[[ -n "$1" && -z "$2" ]] || error_exit 'Incorrect number of arguments for the create command'
|
||||
|
||||
# Store the the absolute path of the mount point
|
||||
mountpoint="$(readlink -f "$1")"
|
||||
|
||||
# Exit with an error if the mount point does not exist or isn't a directory
|
||||
[[ -e "$mountpoint" ]] || error_exit "${c_m}$mountpoint${c_w} does not exist"
|
||||
[[ -d "$mountpoint" ]] || error_exit "${c_m}$mountpoint${c_w} is not a directory"
|
||||
|
||||
# Check the list of mounts for the mount point
|
||||
mount=$(grep "$mountpoint" /proc/mounts)
|
||||
|
||||
# Exit with an error if the mount point isn't in the list of mounts
|
||||
[[ -n "$mount" ]] || error_exit "${c_m}$mountpoint${c_w} is not mounted"
|
||||
|
||||
# Retrieve the name of the container
|
||||
container_path="${mount/ *}"
|
||||
|
||||
# Retrieve the loop device associated with the mount
|
||||
loopdev="${container_path/*\//\/dev\/}"
|
||||
|
||||
# Exit with an error if the container_path doesn't exist
|
||||
[[ -e "$container_path" ]] || error_exit "The mount does not appear to be a decrypted container"
|
||||
|
||||
# Unmount the mount point
|
||||
umount "$mountpoint" || error_exit "Unable to unmount ${c_m}$mountpoint"
|
||||
|
||||
# Close the decrypted image
|
||||
luks_close "$loopdev" "${container_path/*\/}"
|
||||
}
|
||||
|
||||
# Exit with an error on ctrl-c
|
||||
trap 'error_exit "$scriptname has been killed"' SIGINT SIGQUIT
|
||||
|
||||
# Check for root
|
||||
[[ "$UID" -ne 0 ]] && errorquit "run with root permission\n"
|
||||
(( UID == 0 )) || error_exit 'Must be run with root permissions'
|
||||
|
||||
# Check dependencies
|
||||
[[ `type -P dd` ]] || errorquit "Error: The 'dd' program is missing"
|
||||
[[ `type -P losetup` ]] || errorquit "Error: The 'losetup' program is missing"
|
||||
[[ `type -P cryptsetup` ]] || errorquit "Error: The 'cryptsetup' program is missing"
|
||||
[[ `type -P mkfs` ]] || errorquit "Error: The 'mkfs' program is missing"
|
||||
# Dependencies
|
||||
deps=('dd' 'losetup' 'cryptsetup' 'mkfs')
|
||||
|
||||
# Load modules if they aren't present
|
||||
[[ `lsmod | grep loop` ]] || echo "loading 'loop' module"; modprobe loop || errorquit "Error: failed to load 'loop' module"
|
||||
[[ `lsmod | grep dm_mod` ]] || echo "loading 'dm_mod' module"; modprobe dm_mod || errorquit "Error: failed to load 'dm_mod' module"
|
||||
# Check for missing dependencies
|
||||
declare -a missing_deps=()
|
||||
|
||||
if [ -z "$1" ]; then
|
||||
usage; exit 1
|
||||
elif [ ! "$1" = "c" -a ! "$1" = "m" -a ! "$1" = "u" ]; then
|
||||
errorquit "syntax"
|
||||
fi
|
||||
for dep in "${deps[@]}"; do
|
||||
type -P "$dep" >/dev/null \
|
||||
|| missing_deps=( "${missing_deps[@]}" "$dep" )
|
||||
done
|
||||
|
||||
case "$1" in
|
||||
c)
|
||||
if [ -z "$2" -o -z "$3" -o -z "$4" ]; then errorquit "syntax"; fi
|
||||
[[ -f "$2" ]] && errorquit "$2 already exists"
|
||||
LOOPDEV=`losetup -f`
|
||||
CONTAINER=`echo "$2" | sed s/"[^\/]*\/"//g | sed s/"\.".*$//g`
|
||||
dd bs=1M count="$4" if=/dev/urandom of="$2" || errorquit "couldn't create create image file"
|
||||
losetup "$LOOPDEV" "$2" || errorquit "couldn't setup loop device (${LOOPDEV})"
|
||||
cryptsetup -c aes-xts-plain -y -s 512 luksFormat "$LOOPDEV" || errorquit "couldn't encrypt image file"
|
||||
cryptsetup luksOpen "$LOOPDEV" "$CONTAINER" || errorquit "couldn't decrypt $CONTAINER"
|
||||
mkfs -t "$3" "/dev/mapper/${CONTAINER}" || errorquit "mkfs failed for filesystem type: $3"
|
||||
cryptsetup luksClose "$CONTAINER" || errorquit "couldn't close encryption for $CONTAINER"
|
||||
sleep 1
|
||||
losetup -d "$LOOPDEV" || errorquit "couldn't close loop device (${LOOPDEV})"
|
||||
[[ -n "${missing_deps[*]}" ]] && {
|
||||
error_exit "${c_w}missing dependencies ($(
|
||||
for (( x=0; x < ${#missing_deps[@]}; x++ )); do
|
||||
printf '%s' "$c_m${missing_deps[$x]}$c_c"
|
||||
(( (( x + 1 )) < ${#missing_deps[@]} )) && printf '%s' ', '
|
||||
done
|
||||
)$c_w)"
|
||||
}
|
||||
|
||||
# Load the required modules if not already available
|
||||
modules=('loop' 'dm_mod')
|
||||
|
||||
for module in "${modules[@]}"; do
|
||||
modinfo "$module" >/dev/null 2>&1 || {
|
||||
printf '%s ' "${c_w}Loading module: ${c_m}$module${c_w}..."
|
||||
|
||||
if modprobe "$module" >/dev/null 2>&1; then
|
||||
printf '%s\n' "${c_g}done!${c_c}"
|
||||
else
|
||||
printf '%s\n' "${c_r}failed!${c_c}"
|
||||
error_exit "Unable to load module ${c_m}$module"
|
||||
fi
|
||||
}
|
||||
done
|
||||
|
||||
# Store the option and then drop it from the list of arguments
|
||||
option="$1"
|
||||
shift
|
||||
|
||||
# Run the appropriate function based on the provided option
|
||||
case "$option" in
|
||||
c|-c|--create)
|
||||
create_image "$@"
|
||||
;;
|
||||
m)
|
||||
if [ -z "$2" -o -z "$3" ]; then errorquit "syntax"; fi
|
||||
[[ ! -f "$2" ]] && errorquit "$2 does not exist"
|
||||
[[ -d "$3" ]] || errorquit "$3 does not exist"
|
||||
LOOPDEV=$(losetup -f)
|
||||
CONTAINER=$(echo "$LOOPDEV" | sed s/"[^\/]*\/"//g | sed s/"\.".*$//g)
|
||||
losetup "$LOOPDEV" "$2" || errorquit "couldn't setup loop device (${LOOPDEV})"
|
||||
cryptsetup luksOpen "$LOOPDEV" "$CONTAINER" || errorquit "couldn't decrypt $CONTAINER"
|
||||
mount "/dev/mapper/${CONTAINER}" "$3" || errorquit "couldn't mount /dev/mapper/${CONTAINER} on $3"
|
||||
|
||||
m|-m|--mount)
|
||||
mount_image "$@"
|
||||
;;
|
||||
u)
|
||||
if [ -z "$2" ]; then errorquit "syntax"; fi
|
||||
MOUNT=`mount | grep $(echo "$2" | sed s/"\/"$//)`
|
||||
[[ -z "$MOUNT" ]] && errorquit "$2 is not mounted"
|
||||
LOOPDEV=`echo "$MOUNT" | sed s/\ .*//g | sed s/"\/mapper"//`
|
||||
CONTAINER=`echo "$LOOPDEV" | sed s/"[^\/]*\/"//g | sed s/"\.".*$//g`
|
||||
umount "$2" || errorquit "Couldn't unmount $2"
|
||||
cryptsetup luksClose "$CONTAINER" || errorquit "couldn't close encryption for $CONTAINER"
|
||||
sleep 1
|
||||
losetup -d "$LOOPDEV" || errorquit "couldn't close loop device (${LOOPDEV})"
|
||||
|
||||
u|-u|--unmount)
|
||||
unmount_image "$@"
|
||||
;;
|
||||
generic)
|
||||
usage
|
||||
|
||||
h|-h|--help)
|
||||
usage 0
|
||||
;;
|
||||
|
||||
*)
|
||||
usage 1
|
||||
;;
|
||||
esac
|
||||
|
|
Loading…
Reference in a new issue