Changeset - 1c4602d59bf4
[Not reviewed]
0 1 0
Branko Majic (branko) - 4 years ago 2020-06-29 04:17:24
branko@majic.rs
Key removal will not raise any more questions. Most GnuPG commands are now executed with --batch options (no prompting). Added checks for addkey/rmkey commands to check if any key was specified at all. Implemented the encrypt/decrypt commands (currently they're _very_ destructive.
1 file changed with 89 insertions and 12 deletions:
0 comments (0 inline, 0 general)
openpgp/gitprotect.sh
Show inline comments
 
@@ -34,6 +34,10 @@ for storing the passwords centrally, allowing small geographically disperse
 
teams to exchange them in a secure manner. The utility relies on using GnuPG
 
utility for performing all tasks related to encryption and decryption.
 

	
 
The script works on induvidual directories by keeping the GnuPG keyring used for
 
encryption in the subdirectory .gnupg, and using a sub-directory 'decrypted' for
 
storing unencrypted content.
 

	
 
The following commands are provided for managing the repository/directories:
 

	
 
    init
 
@@ -58,6 +62,17 @@ The following commands are provided for managing the repository/directories:
 

	
 
    Lists the keys from the git repository GnuPG keyring.
 

	
 
    encrypt
 

	
 
    Encrypts all the files from the 'decrypted' sub-directory, and stores them
 
    in the initialised directory. The encrypted files will have the .gpg
 
    extension.
 

	
 
    decrypt
 

	
 
    Decrypts all the files from the current directory, storing them in the
 
    'decrypted' sub-directory. Only the files with extension .gpg are decrypted.
 

	
 
$program accepts the following options:
 

	
 
    -v        show script version and licensing information
 
@@ -140,6 +155,9 @@ function gitprotectConfigured() {
 
#
 
ERR_NOTINGIT=10
 
ERR_NOCONFIG=11
 
ERR_NOKEYARG=12
 
ERR_NODECRYPTDIR=13
 
ERR_NORECIPIENTS=14
 

	
 
# If no arguments were given, just show usage help.
 
if [[ -z $1 ]]; then
 
@@ -173,30 +191,39 @@ gnupgHome="$(pwd)/.gnupg"
 

	
 
if [[ $command == "init" ]]; then
 
    if [[ -d $gnupgHome ]]; then
 
        echo "Directory already set-up."
 
        echo "Directory already set-up." >&2
 
        exit 0
 
    fi
 

	
 
    # Created the local .gnupg directory.
 
    # Create the local .gnupg directory.
 
    mkdir "$gnupgHome"
 
    chmod 700 "$gnupgHome"
 
    gpg2 --homedir "$gnupgHome" --list-keys 2>/dev/null
 

	
 
    # Initialise the GnuPG files in local directory.
 
    gpg2 --batch --homedir "$gnupgHome" --list-keys 2>/dev/null
 
elif [[ $command == "addkey" ]]; then
 
    gitprotectConfigured || exit "$ERR_NOCONFIG"
 

	
 
    # At least one key has to be provided.
 
    if [[ "${#@}" == 0 ]]; then
 
        echo "ERROR: At least one key file or identifier must be specified" >&2
 
        exit "$ERR_NOKEYARG"
 
    fi
 

	
 
    # Process all the keys specified.
 
    for key in "$@"; do
 
        # First try accessing a file by the given key name. Otherwise treat it
 
        # as key identifier.
 
        if [[ -f $key ]]; then
 
            if ! gpg2 --homedir "$gnupgHome" --import "$key"; then
 
            if ! gpg2 --batch --homedir "$gnupgHome" --import "$key"; then
 
                echo "ERROR: Failed to add key from file '$key'." >&2
 
            fi
 
        else
 
            if ! gpg2 --list-keys "$key" >/dev/null 2>&1; then
 
            if ! gpg2 --batch --list-keys "$key" >/dev/null 2>&1; then
 
                echo "WARN: Key with identifier '$key' not found in user's GnuPG keyring. Skipping." >&2
 
            else
 
                if ! gpg2 --armor --export "$key" | gpg2 --homedir "$gnupgHome" --import; then
 
                ! gpg2 --batch --armor --export "$key" | gpg2 --batch --homedir "$gnupgHome" --import
 
                if [[ ${PIPESTATUS[0]} != 0 ]]; then
 
                    echo "ERROR: Failed to add key with identifier '$key')." >&2
 
                fi
 
            fi
 
@@ -205,19 +232,69 @@ elif [[ $command == "addkey" ]]; then
 
elif [[ $command = "rmkey" ]]; then
 
    gitprotectConfigured || exit "$ERR_NOCONFIG"
 

	
 
    # At least one key has to be provided.
 
    if [[ "${#@}" == 0 ]]; then
 
        echo "ERROR: At least one key file or identifier must be specified" >&2
 
        exit "$ERR_NOKEYARG"
 
    fi
 

	
 
    # Process all the keys specified.
 
    for key in "$@"; do
 
        if ! gpg2 --homedir "$gnupgHome" --list-key "$key" 2>/dev/null; then
 
        if ! gpg2 --batch --homedir "$gnupgHome" --list-key "$key" 2>/dev/null; then
 
            echo "WARN: Key with identifier '$key' not found in git repository directory's GnuPG keyring. Skipping" >&2
 
        else
 
            if ! gpg2 --homedir "$gnupgHome" --yes --delete-key "$key"; then
 
                echo "ERROR: Failed to remove the key with identifier '$key'." >&2
 
            fi
 
        elif ! gpg2 --batch --homedir "$gnupgHome" --yes --delete-key "$key"; then
 
            echo "ERROR: Failed to remove the key with identifier '$key'." >&2
 
        fi
 
    done
 
elif [[ $command = "listkeys" ]]; then
 
    gitprotectConfigured || exit "$ERR_NOCONFIG"
 
    gpg2 --fingerprint --homedir "$gnupgHome" --list-public-keys --keyid-format long
 
    gpg2 --batch --homedir "$gnupgHome" --list-public-keys --keyid-format long
 
elif [[ $command = "encrypt" ]]; then
 
    gitprotectConfigured || exit "$ERR_NOCONFIG"
 

	
 
    # Verify that the directory with unencrypted files exists.
 
    if [[ ! -d "decrypted/" ]]; then
 
        echo "ERROR: Nothing to encrypt. sub-directory 'decrypted' does not exist."
 
        exit "$ERR_NODECRYPTDIR"
 
    fi
 

	
 
    # Set-up the list of recipients. Read the information about each public
 
    # sub-key from the local keyring.
 
    while read key_validity key_id key_capabilities; do
 
        # Only use non-expired sub-keys that have encryption capability.
 
        if [[ $key_validity != e && $key_capabilities =~ .*e.* ]]; then
 
            recipients+=("-r" "$key_id")
 
        fi
 
    done < <(gpg2 --homedir "$gnupgHome" --list-public-keys --with-colons | grep '^sub' | awk 'BEGIN { FS = ":" } ; { print $2, $5, $12 }')
 

	
 
    # Make sure that we have at least a single recipient.
 
    if [[ "${#recipients[@]}" == 0 ]]; then
 
        echo "ERROR: No suitable recipients were found in the keyring." >&2
 
        exit "$ERR_NORECIPIENTS"
 
    fi
 

	
 
    # Encrypt every file from the decrypted sub-directory.
 
    while read filePath; do
 
        filename=$(basename "$filePath")
 
        cat "$filePath" | gpg2 --trust-model always --batch --homedir "$gnupgHome" \
 
            --armor "${recipients[@]}" --encrypt > "${filename}.gpg"
 
    done < <(find "decrypted/" -maxdepth 1 -type f)
 
elif [[ $command = "decrypt" ]]; then
 
    gitprotectConfigured || exit "$ERR_NOCONFIG"
 

	
 
    # Create the sub-directory that will contain the decrypted data.
 
    mkdir -p "decrypted/"
 

	
 
    # Process each GnuPG-encrypted file.
 
    while read filePath; do
 
        filename=$(basename "$filePath" ".gpg")
 

	
 
        # Remove the "decrypted" file if decryption had failed.
 
        if ! gpg2 --decrypt "$filePath" > "decrypted/$filename"; then
 
            echo "ERROR: Failed to decrypt file '$filepath'. No private key available." >&2
 
            rm "decrypted/$filename"
 
        fi
 
    done < <(find . -maxdepth 1 -name '*.gpg')
 
else
 
    echo "ERROR: Unsupported command '$command'" >&2
 
fi
0 comments (0 inline, 0 general)