#!/bin/bash umask 077 hashes=(sha sha1 mdc2 ripemd160 sha224 sha256 sha384 sha512 md4 md5 dss1) hash_dir=$(mktemp -d) function die() { echo "$*" >&2 exit 1 } if (( $# != 2));then die "usage: overonion e|d keyfile" fi mode=$1 if [[ "$mode" != e && "$mode" != d ]];then die "Use 'e' for encrypt or 'd' for decrypt" fi keyfile=$2 if [[ ! -e "$keyfile" ]];then die "Keyfile not found" fi if [[ ! -r "$keyfile" ]];then die "Cannot read keyfile" fi num_layers=$(wc -l < "$keyfile") if (( num_layers < 20 ));then die "Keyfile doesn't have enough layers to be an onion" fi if [[ "$mode" == e ]];then first_layer=$num_layers next_layer=-1 openssl_decrypt="" else first_layer=1 next_layer=1 openssl_decrypt="-d" fi function verify_hash() { (( $(wc -l < "$1") == 2 && $(uniq "$1" | wc -l) == 1 )) } function go() { layer=$1 if (( layer == 0 || layer > num_layers ));then cat else operation=$(sed -n "${layer}{;s/ .*//;p;}" "$keyfile") if [[ "$operation" == openssl-enc ]];then openssl enc $openssl_decrypt "-$(sed -rn "${layer}s/[^ ]+ ([^ ]+) .*/\\1/p" "$keyfile")" \ -pass fd:37 37< <(sed -rn "${layer}s/^[^ ]+ [^ ]+ //p" "$keyfile") elif [[ "$operation" == reverse ]];then reverse elif [[ "$operation" == openssl-dgst ]];then tee >(sed -rn "${layer}s/^[^ ]+ [^ ]+ //p" "$keyfile" > "$hash_dir/$layer" openssl dgst -binary "-$(sed -rn "${layer}s/[^ ]+ ([^ ]+) .*/\\1/p" "$keyfile")" | base64 --wrap=0 | sed 's/$/\n/' >> "$hash_dir/$layer" # Dying here doesn't terminate the pipeline. :( verify_hash "$hash_dir/$layer" || die "Hash check $layer failed" ) else die "Unknown operation" fi | go $(( layer + next_layer )) fi } function record_hashes() { if [[ "$mode" == d ]] || (( $# < 2 ));then cat else stage=$1 hash=$2 shift 2 tee >(openssl dgst -binary "-$hash" | base64 --wrap=0 | sed "s/^/openssl-dgst $hash /;s/$/\n/" > "$hash_dir/$stage-$hash") | record_hashes "$stage" "$@" fi } record_hashes inner "${hashes[@]}" | go "$first_layer" | record_hashes outer "${hashes[@]}" 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" cat "$hash_dir"/outer-* "$key_aside" "$hash_dir"/inner* > "$keyfile" shred -u "$key_aside" rmdir "$key_aside_dir" else # Verify the hashes for hash_result in "$hash_dir"/*;do verify_hash "$hash_result" || die "Hash check $(basename "$hash_result") failed" done fi rm -r "$hash_dir"