diff --git a/README.md b/README.md index cc7263b..b4088bd 100644 --- a/README.md +++ b/README.md @@ -152,12 +152,12 @@ by running the `--display` command line option: The current repository was configured using transcrypt v0.2.0 and has the following configuration: - CIPHER: aes-256-cbc + CIPHER: aes-256-cbc:pbkdf2:1024 PASSWORD: correct horse battery staple Copy and paste the following command to initialize a cloned repository: - transcrypt -c aes-256-cbc -p 'correct horse battery staple' + transcrypt -c aes-256-cbc:pbkdf2:1024 -p 'correct horse battery staple' Once transcrypt has stored the matching credentials, it will force a checkout of any exising encrypted files in order to decrypt them. @@ -184,7 +184,7 @@ re-configure transcrypt with the new credentials. $ transcrypt --flush-credentials $ git fetch origin $ git merge origin/main - $ transcrypt -c aes-256-cbc -p 'the-new-password' + $ transcrypt -c aes-256-cbcaes-256-cbc:pbkdf2:1024 -p 'the-new-password' ### Command Line Options @@ -194,8 +194,10 @@ directory. transcrypt [option...] -c, --cipher=CIPHER - the symmetric cipher to utilize for encryption; - defaults to aes-256-cbc + the symmetric cipher to utilize for encryption, can + include cipher, key derivation, and iteration components + separated by ':'; + defaults to aes-256-cbc:pbkdf2:1024 -p, --password=PASSWORD the password to derive the key from; diff --git a/sensitive_file b/sensitive_file index 547ad71..1419dcf 100644 --- a/sensitive_file +++ b/sensitive_file @@ -1,40 +1,40 @@ -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 -L/aeTVBw2BnDs2K48meuFw== +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 +Ax3RhJMLF5+uXPoslVOEIQ== diff --git a/transcrypt b/transcrypt index 510157e..8ba6481 100755 --- a/transcrypt +++ b/transcrypt @@ -16,10 +16,10 @@ set -euo pipefail ##### CONSTANTS # the release version of this script -readonly VERSION='2.2.0-pre' +readonly VERSION='3.0-pre' # the default cipher to utilize -readonly DEFAULT_CIPHER='aes-256-cbc' +readonly DEFAULT_CIPHER='aes-256-cbc:pbkdf2:1024' ##### FUNCTIONS @@ -52,6 +52,7 @@ realpath() { } # establish repository metadata and directory handling +# shellcheck disable=SC2155 gather_repo_metadata() { # whether or not transcrypt is already configured readonly CONFIGURED=$(git config --get --local transcrypt.version 2>/dev/null) @@ -130,21 +131,35 @@ git_clean() { if [[ $firstbytes == "U2FsdGVk" ]]; then cat "$tempfile" else - cipher=$(git config --get --local transcrypt.cipher) + cipher_key_deriv_iter=$(git config --get --local transcrypt.cipher) + cipher=$(echo "$cipher_key_deriv_iter" | awk 'BEGIN { FS = ":" }; { print $1 }') + key_deriv=$(echo "$cipher_key_deriv_iter" | awk 'BEGIN { FS = ":" }; { print $2 }') + iter=$(echo "$cipher_key_deriv_iter" | awk 'BEGIN { FS = ":" }; { print $3 }') password=$(git config --get --local transcrypt.password) openssl_path=$(git config --get --local transcrypt.openssl-path) salt=$("${openssl_path}" dgst -hmac "${filename}:${password}" -sha256 "$tempfile" | tr -d '\r\n' | tail -c16) - ENC_PASS=$password "$openssl_path" enc "-${cipher}" -md MD5 -pass env:ENC_PASS -e -a -S "$salt" -in "$tempfile" + if [[ -z "$key_deriv" ]]; then + ENC_PASS=$password "$openssl_path" enc "-${cipher}" -md MD5 -pass env:ENC_PASS -e -a -S "$salt" -in "$tempfile" + else + ENC_PASS=$password "$openssl_path" enc "-${cipher}" "-${key_deriv}" -iter "${iter}" -md SHA512 -pass env:ENC_PASS -e -a -S "$salt" -in "$tempfile" + fi fi } git_smudge() { tempfile=$(mktemp 2>/dev/null || mktemp -t tmp) trap 'rm -f "$tempfile"' EXIT - cipher=$(git config --get --local transcrypt.cipher) + cipher_key_deriv_iter=$(git config --get --local transcrypt.cipher) + cipher=$(echo "$cipher_key_deriv_iter" | awk 'BEGIN { FS = ":" }; { print $1 }') + key_deriv=$(echo "$cipher_key_deriv_iter" | awk 'BEGIN { FS = ":" }; { print $2 }') + iter=$(echo "$cipher_key_deriv_iter" | awk 'BEGIN { FS = ":" }; { print $3 }') password=$(git config --get --local transcrypt.password) openssl_path=$(git config --get --local transcrypt.openssl-path) - tee "$tempfile" | ENC_PASS=$password "$openssl_path" enc "-${cipher}" -md MD5 -pass env:ENC_PASS -d -a 2>/dev/null || cat "$tempfile" + if [[ -z "$key_deriv" ]]; then + tee "$tempfile" | ENC_PASS=$password "$openssl_path" enc "-${cipher}" -md MD5 -pass env:ENC_PASS -d -a 2>/dev/null || cat "$tempfile" + else + tee "$tempfile" | ENC_PASS=$password "$openssl_path" enc "-${cipher}" "-${key_deriv}" -iter "${iter}" -md SHA512 -pass env:ENC_PASS -d -a 2>/dev/null || cat "$tempfile" + fi } git_textconv() { @@ -153,10 +168,17 @@ git_textconv() { if [[ ! -s $filename ]]; then return fi - cipher=$(git config --get --local transcrypt.cipher) + cipher_key_deriv_iter=$(git config --get --local transcrypt.cipher) + cipher=$(echo "$cipher_key_deriv_iter" | awk 'BEGIN { FS = ":" }; { print $1 }') + key_deriv=$(echo "$cipher_key_deriv_iter" | awk 'BEGIN { FS = ":" }; { print $2 }') + iter=$(echo "$cipher_key_deriv_iter" | awk 'BEGIN { FS = ":" }; { print $3 }') password=$(git config --get --local transcrypt.password) openssl_path=$(git config --get --local transcrypt.openssl-path) - ENC_PASS=$password "$openssl_path" enc "-${cipher}" -md MD5 -pass env:ENC_PASS -d -a -in "$filename" 2>/dev/null || cat "$filename" + if [[ -z "$key_deriv" ]]; then + ENC_PASS=$password "$openssl_path" enc "-${cipher}" -md MD5 -pass env:ENC_PASS -d -a -in "$filename" 2>/dev/null || cat "$filename" + else + ENC_PASS=$password "$openssl_path" enc "-${cipher}" "-${key_deriv}" -iter "${iter}" -md SHA512 -pass env:ENC_PASS -d -a -in "$filename" 2>/dev/null || cat "$filename" + fi } # shellcheck disable=SC2005,SC2002,SC2181 @@ -239,17 +261,20 @@ validate_cipher() { list_cipher_commands="${openssl_path} list -cipher-commands" fi + local cipher_only + cipher_only=$(echo "$cipher" | cut -d: -f1) + local supported - supported=$($list_cipher_commands | tr -s ' ' '\n' | grep -Fx "$cipher") || true + supported=$($list_cipher_commands | tr -s ' ' '\n' | grep -Fx "$cipher_only") || true if [[ ! $supported ]]; then if [[ $interactive ]]; then - printf '"%s" is not a valid cipher; choose one of the following:\n\n' "$cipher" + printf '"%s" is not a valid cipher; choose one of the following:\n\n' "$cipher_only" $list_cipher_commands | column -c 80 printf '\n' cipher='' else # shellcheck disable=SC2016 - die 1 '"%s" is not a valid cipher; see `%s`' "$cipher" "$list_cipher_commands" + die 1 '"%s" is not a valid cipher; see `%s`' "$cipher_only" "$list_cipher_commands" fi fi } @@ -999,7 +1024,7 @@ rekey='' show_file='' uninstall='' upgrade='' -openssl_path='openssl' +openssl_path=$(git config --get --local transcrypt.openssl-path || echo 'openssl') # used to bypass certain safety checks requires_existing_config=''