#!/bin/bash# Public/private key scheme works great if it can encrypt large files but unfortunately only
# file up to 1024 bytes can be encrypted using a public key. Secret key scheme can deal with
# big files but the same key is used for encrypting and decrypting. Therefore the best practice 
# to do is to combine these two methods together: encrypt data with the secret key (not to be
# confused with private key) then encrypt the secret key with public key. problem solved.
#### encrypt procedures
# [ 1 ] create a 1000-byte random key
# [ 2 ] encrypt the destination (either a file or folder) then remove the original secret key
# [ 3 ] encrypt the secret key generated at step 1 with the public key
# [ 4 ] now the secret key and the data file are both encrypted
#### decrypt procedures
# [ 1 ] decrypt secret key with the private key
# [ 2 ] decrypt the data file with the decrypted secret key
# [ 3 ] delete secret key
#in order to use this script, a pair of public/private keys need to be created first:
# for example:
# $ mkdir ~/.ssl
# $ cd ~/.ssl
# $ openssl genrsa -out private.pem 4096 
# $ chmod 600 private.pem
# $ openssl rsa -in private.pem -out public.pem -outform PEM -pubout
# 
# the private key privated.pem should be stored in a secure location as once it's compromised,
# all the efforts to protect sensitive data will be useless.
declare -rx SCRIPT=${0##*/}
TMP=`mktemp -u -p . XXX`
TMP=${TMP##*/}
KEY=secret.$TMP.key
DEBUG=1
usage() {
    printf "usages:\n"
    printf "\t%s enc datafile public_key [ output_path ]\n" $SCRIPT
    printf "\t%s enc datadir/ public_key [ output_path ]\n" $SCRIPT
    printf "\t%s dec datafile.bf private_key [ output_path ]\n" $SCRIPT
}
if [ $# -lt 3 ]; then
    usage
    exit
fi
case $1 in
    enc)
        TIME_START=$(date "+%s")
        TARGET=$2
        TARGET=${TARGET%/}    #remove trailing / if any
        PUB_KEY=$3
        [ $# -gt 3 ] && OUT_DIR=$4 || OUT_DIR=.
        OUT_DIR=${OUT_DIR%/}    #remove trailing / if any
        ID=`mktemp -u -p . XXXX`
        ID=${ID##*/}
        OUTPUT=$OUT_DIR/${TARGET##*/}.bf.$ID
        [ ! -f $PUB_KEY -o ! -d $OUT_DIR ] && \
        printf "Check if $PUB_KEY or $OUT_DIR/ exists\n" && exit 151
        #make sure the key is only readable by the script owner
        touch $KEY && chmod 600 $KEY
        KEY=$OUT_DIR/secret.key.$ID
        ENC_KEY=$OUT_DIR/secret.key.rsa.$ID
        dd if=/dev/random of=$KEY bs=100 count=1
        #encrypt the key
        G1="openssl rsautl -encrypt -inkey $PUB_KEY -pubin -in $KEY -out $ENC_KEY"
        [ $DEBUG -eq 1 ] && echo $G1
        eval $G1
        G="tar -zcf - $TARGET|openssl enc -blowfish -pass file:$KEY|dd of=$OUTPUT"
        [ $DEBUG -eq 1 ] && echo $G || echo "Encrypting ..."
        eval $G && rm -f $KEY
        TIME_END=$(date "+%s")
        SECONDS_SPENT=$(expr $TIME_END - $TIME_START)
        printf "Encryption Summary:\n"
        printf "\tData: %s\n" $OUTPUT
        printf "\tEncrypted Key: %s\n" $ENC_KEY
        printf "\tTotal Time Elapsed: $SECONDS_SPENT seconds.\n"
        exit 0
        ;;
    dec)
        TIME_START=$(date "+%s")
        TARGET=$2
        ID=${TARGET##*.}
        PRIV_KEY=$3
        [ $# -gt 3 ] && OUT_DIR=$4 || OUT_DIR=.
        #remove trailing / if any
        OUT_DIR=${OUT_DIR%/}
        [ ! -f $PRIV_KEY ] && printf "Missing valid private key.\n" && exit 152
        if [ ! -d $OUT_DIR ]; then
            if [ -f $OUT_DIR ]; then
                printf "$OUT_DIR exists and it's a file!\n"
                exit 155
            else
                printf "Creating non-existing directory $OUT_DIR\n" && mkdir $OUT_DIR
            fi
        fi
        [ ! -f $TARGET ] && printf "$TARGET does not exist or is not a file" && exit 153
        ORIG_DIR=$(dirname $TARGET)
        ENC_KEY=$ORIG_DIR/secret.key.rsa.$ID
        KEY=$OUT_DIR/secret.key.$ID
        [ ! -f $ENC_KEY ] && printf "Encrypted secret key $ENC_KEY is missing, \
        it should be in the same path as $TARGET" && exit 154
        G="openssl rsautl -decrypt -inkey $PRIV_KEY -in $ENC_KEY -out $KEY"
        [ $DEBUG -eq 1 ] && echo $G
        eval $G
        chmod 600 $KEY
        G1="dd if=$TARGET|openssl enc -d -blowfish -pass file:$KEY|tar xzf - -C $OUT_DIR"
        [ $DEBUG -eq 1 ] && echo $G1 || echo "Decrypting ..."
        eval $G1 && rm -f $KEY
        TIME_END=$(date "+%s")
        SECONDS_SPENT=$(expr $TIME_END - $TIME_START)
        printf "Decryption Summary:\n"
        printf "\tData Location: %s\n" $OUT_DIR
        printf "\tEncrypted Key: %s\n" $ENC_KEY
        printf "\tTotal Time Elapsed: $SECONDS_SPENT seconds.\n"
        exit 0
        ;;
    *)
        usage
        exit 152
esac