#!/bin/bash
+umask 077
+
+hash_dir=$(mktemp -d)
+
function die() {
echo "$*" >&2
exit 1
die "Keyfile doesn't have enough layers to be an onion"
fi
+hash_fields=$(awk '/^openssl-dgst / { print NF }' "$keyfile" | uniq )
+
if [[ "$mode" == e ]];then
first_layer=$num_layers
next_layer=-1
openssl_decrypt=""
+ if [[ "$hash_fields" != 4 ]];then
+ die "Refusing to encrypt with already-used key"
+ fi
else
first_layer=1
next_layer=1
openssl_decrypt="-d"
+ if [[ "$hash_fields" != 5 ]];then
+ die "Key does not appear to have been used for encryption (it has no embedded hashes). Refusing to decrypt."
+ fi
fi
+function keyline() {
+ awk -vline="$1" 'NR == line' "$keyfile"
+}
+
+function keyfield() {
+ awk -vline="$1" -vfield="$2" 'NR == line { print $field }' "$keyfile"
+}
+
function go() {
layer=$1
if (( layer == 0 || layer > num_layers ));then
cat
else
- openssl enc $openssl_decrypt "-$(sed -n "${layer}s/ .*//p" "$keyfile")" \
- -pass fd:37 37< <(sed -n "${layer}s/^[^ ]* //p" "$keyfile") |
- go $(( layer + next_layer ))
+ operation=$(keyfield "$layer" 1)
+ if [[ "$operation" == openssl-enc ]];then
+ openssl enc $openssl_decrypt "-$(keyfield "$layer" 2)" \
+ -nosalt -pass fd:37 37< <(keyfield "$layer" 3)
+ elif [[ "$operation" == reverse ]];then
+ "$(dirname "$0")/reverse"
+ elif [[ "$operation" == openssl-dgst ]];then
+ tee >(echo "$(keyline "$layer") $(
+ {
+ keyfield "$layer" 3 | base64 -d
+ cat
+ keyfield "$layer" 4 | base64 -d
+ } |
+ openssl dgst -binary "-$(keyfield "$layer" 2)" |
+ base64 --wrap=0)" > "$hash_dir/$layer")
+ else
+ die "Unknown operation"
+ fi |
+ go $(( layer + next_layer ))
fi
}
go "$first_layer"
+
+for hash_result in "$hash_dir"/*;do
+ layer=$(basename "$hash_result")
+ if [[ "$mode" == e ]];then
+ # Add the hashes to keyfile
+ key_aside_dir=$(mktemp -d "$keyfile.XXXXXXXXXX")
+ key_aside="$key_aside_dir/key.orig"
+ mv "$keyfile" "$key_aside"
+ sed "${layer}s,.*,$(< "$hash_result")," "$key_aside" > "$keyfile"
+ shred -u "$key_aside"
+ rmdir "$key_aside_dir"
+ else
+ # Verify the hashes
+ if [[ "$(awk '{ print $5 == $6 ? "hash ok" : "mismatch" }' "$hash_result")" != "hash ok" ]];then
+ die "Hash check $layer failed"
+ fi
+ fi
+done
+
+rm -r "$hash_dir"