-
Notifications
You must be signed in to change notification settings - Fork 6
/
cryptobox
executable file
·265 lines (206 loc) · 8.63 KB
/
cryptobox
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
#!/usr/bin/env bash
#
# CryptoBox
#
# A script that makes it easy to create, mount
# and unmount encrypted images in Linux using LUKS
#
# Written by Kevin MacMartin
#
# Released under the MIT license
#
[[ -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
}
# The name of the script
scriptname="${0/*\/}"
# Display uage information
function usage {
printf '%s\n\n' "${c_b}$scriptname${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_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_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_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}"
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 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 --pbkdf argon2id -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
[[ ! -e "$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 == 0 )) || error_exit 'Must be run with root permissions'
# Dependencies
deps=('dd' 'losetup' 'cryptsetup' 'mkfs')
# Check for missing dependencies
declare -a missing_deps=()
for dep in "${deps[@]}"; do
type -P "$dep" >/dev/null \
|| missing_deps=("${missing_deps[@]}" "$dep")
done
[[ -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|-m|--mount)
mount_image "$@"
;;
u|-u|--unmount)
unmount_image "$@"
;;
h|-h|--help)
usage 0
;;
*)
usage 1
;;
esac