Skip to content

Support OpenSSL 3 which has changed behaviour for "Salted__" prefix #135

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Jun 14, 2022
2 changes: 1 addition & 1 deletion .github/workflows/run-bats-core-tests.yml
Original file line number Diff line number Diff line change
@@ -28,7 +28,7 @@ jobs:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-18.04, ubuntu-20.04, macos-latest]
os: [ubuntu-18.04, ubuntu-20.04, ubuntu-22.04, macos-latest]

steps:
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -29,6 +29,8 @@ The format is based on [Keep a Changelog][1], and this project adheres to

### Fixed

- Remain compatible with OpenSSL versions 3 and above which changes the way
explicit salt values are expressed in ciphertext (#133)
- Ensure Git index is up-to-date before checking for dirty repo, to avoid
failures seen in CI systems where the repo seems dirty when it isn't. (#37)
- Respect Git `core.hooksPath` setting when installing the pre-commit hook. (#104)
15 changes: 7 additions & 8 deletions tests/test_crypt.bats
Original file line number Diff line number Diff line change
@@ -62,7 +62,7 @@ function check_repo_is_clean {

run ../transcrypt --list
[ "$status" -eq 0 ]
[ "${lines[0]}" = "sensitive_file" ]
[[ "${output}" = *"sensitive_file" ]]
}

@test "crypt: transcrypt --uninstall leaves decrypted file and repo dirty" {
@@ -117,7 +117,6 @@ function check_repo_is_clean {

# Git internal copy is encrypted
run git show HEAD:"$FILENAME" --no-textconv
echo "${lines}"
[ "$status" -eq 0 ]
[ "${lines[0]}" = "$SECRET_CONTENT_ENC" ]

@@ -130,12 +129,12 @@ function check_repo_is_clean {
# git ls-crypt lists encrypted file
run git ls-crypt
[ "$status" -eq 0 ]
[ "${lines[0]}" = "$FILENAME" ]
[[ "${output}" = *"$FILENAME" ]]

# transcrypt --list lists encrypted file"
run ../transcrypt --list
[ "$status" -eq 0 ]
[ "${lines[0]}" = "$FILENAME" ]
[[ "${output}" = *"$FILENAME" ]]

rm "$FILENAME"
}
@@ -167,12 +166,12 @@ function check_repo_is_clean {
# git ls-crypt lists encrypted file
run git ls-crypt
[ "$status" -eq 0 ]
[ "${lines[0]}" = "$FILENAME" ]
[[ "${output}" = *"$FILENAME" ]]

# transcrypt --list lists encrypted file"
run ../transcrypt --list
[ "$status" -eq 0 ]
[ "${lines[0]}" = "$FILENAME" ]
[[ "${output}" = *"$FILENAME" ]]

rm "$FILENAME"
}
@@ -201,12 +200,12 @@ function check_repo_is_clean {
# git ls-crypt lists encrypted file
run git ls-crypt
[ "$status" -eq 0 ]
[ "${lines[0]}" = "$FILENAME" ]
[[ "${output}" = *"$FILENAME" ]]

# transcrypt --list lists encrypted file"
run ../transcrypt --list
[ "$status" -eq 0 ]
[ "${lines[0]}" = "$FILENAME" ]
[[ "${output}" = *"$FILENAME" ]]

rm "$FILENAME"
}
32 changes: 19 additions & 13 deletions tests/test_init.bats
Original file line number Diff line number Diff line change
@@ -11,7 +11,7 @@ SETUP_SKIP_INIT_TRANSCRYPT=1
# Use literal command not function to confirm command works at least once
run ../transcrypt --cipher=aes-256-cbc --password='abc 123' --yes
[ "$status" -eq 0 ]
[ "${lines[0]}" = "The repository has been successfully configured by transcrypt." ]
[[ "${output}" = *"The repository has been successfully configured by transcrypt."* ]]
}

@test "init: creates .gitattributes" {
@@ -58,10 +58,10 @@ SETUP_SKIP_INIT_TRANSCRYPT=1

run ../transcrypt --display
[ "$status" -eq 0 ]
[ "${lines[0]}" = "The current repository was configured using transcrypt version $VERSION" ]
[ "${lines[5]}" = " CIPHER: aes-256-cbc" ]
[ "${lines[6]}" = " PASSWORD: abc 123" ]
[ "${lines[8]}" = " transcrypt -c aes-256-cbc -p 'abc 123'" ]
[[ "${output}" = *"The current repository was configured using transcrypt version $VERSION"* ]]
[[ "${output}" = *" CIPHER: aes-256-cbc"* ]]
[[ "${output}" = *" PASSWORD: abc 123"* ]]
[[ "${output}" = *" transcrypt -c aes-256-cbc -p 'abc 123'"* ]]
}

@test "init: show details for -d" {
@@ -70,10 +70,10 @@ SETUP_SKIP_INIT_TRANSCRYPT=1

run ../transcrypt -d
[ "$status" -eq 0 ]
[ "${lines[0]}" = "The current repository was configured using transcrypt version $VERSION" ]
[ "${lines[5]}" = " CIPHER: aes-256-cbc" ]
[ "${lines[6]}" = " PASSWORD: abc 123" ]
[ "${lines[8]}" = " transcrypt -c aes-256-cbc -p 'abc 123'" ]
[[ "${output}" = *"The current repository was configured using transcrypt version $VERSION"* ]]
[[ "${output}" = *" CIPHER: aes-256-cbc"* ]]
[[ "${output}" = *" PASSWORD: abc 123"* ]]
[[ "${output}" = *" transcrypt -c aes-256-cbc -p 'abc 123'"* ]]
}

@test "init: respects core.hooksPath setting" {
@@ -87,10 +87,10 @@ SETUP_SKIP_INIT_TRANSCRYPT=1
VERSION=$(../transcrypt -v | awk '{print $2}')
run ../transcrypt --display
[ "$status" -eq 0 ]
[ "${lines[0]}" = "The current repository was configured using transcrypt version $VERSION" ]
[ "${lines[5]}" = " CIPHER: aes-256-cbc" ]
[ "${lines[6]}" = " PASSWORD: abc 123" ]
[ "${lines[8]}" = " transcrypt -c aes-256-cbc -p 'abc 123'" ]
[[ "${output}" = *"The current repository was configured using transcrypt version $VERSION"* ]]
[[ "${output}" = *" CIPHER: aes-256-cbc"* ]]
[[ "${output}" = *" PASSWORD: abc 123"* ]]
[[ "${output}" = *" transcrypt -c aes-256-cbc -p 'abc 123'"* ]]
}

@test "init: transcrypt.openssl-path config setting defaults to 'openssl'" {
@@ -136,6 +136,9 @@ SETUP_SKIP_INIT_TRANSCRYPT=1
}

@test "init: transcrypt.crypt-dir config setting is applied during init" {
# Clear tmp crypt/ directory, in case junk was left there from prior test runs
rm -fR /tmp/crypt/

# Set a custom location for the crypt/ directory
git config transcrypt.crypt-dir /tmp/crypt

@@ -149,6 +152,9 @@ SETUP_SKIP_INIT_TRANSCRYPT=1
}

@test "crypt: transcrypt.crypt-dir config setting produces working scripts" {
# Clear tmp crypt/ directory, in case junk was left there from prior test runs
rm -fR /tmp/crypt/

# Set a custom location for the crypt/ directory
git config transcrypt.crypt-dir /tmp/crypt

24 changes: 17 additions & 7 deletions tests/test_not_inited.bats
Original file line number Diff line number Diff line change
@@ -35,12 +35,22 @@ SETUP_SKIP_INIT_TRANSCRYPT=1

@test "not inited: no files listed for --list" {
run ../transcrypt --list
[ "${lines[0]}" = "" ]
if [[ "${output}" = *"WARNING"* ]]; then
[ "${lines[0]}" = "*** WARNING : deprecated key derivation used." ]
[ "${lines[1]}" = "Using -iter or -pbkdf2 would be better." ]
else
[ "${lines[0]}" = "" ]
fi
}

@test "not inited: no files listed for -l" {
run ../transcrypt -l
[ "${lines[0]}" = "" ]
if [[ "${output}" = *"WARNING"* ]]; then
[ "${lines[0]}" = "*** WARNING : deprecated key derivation used." ]
[ "${lines[1]}" = "Using -iter or -pbkdf2 would be better." ]
else
[ "${lines[0]}" = "" ]
fi
}


@@ -49,30 +59,30 @@ SETUP_SKIP_INIT_TRANSCRYPT=1
@test "not inited: error on --display" {
run ../transcrypt --display
[ "$status" -ne 0 ]
[ "${lines[0]}" = "transcrypt: the current repository is not configured" ]
[[ "${output}" = *"transcrypt: the current repository is not configured"* ]]
}

@test "not inited: error on -d" {
run ../transcrypt -d
[ "$status" -ne 0 ]
[ "${lines[0]}" = "transcrypt: the current repository is not configured" ]
[[ "${output}" = *"transcrypt: the current repository is not configured"* ]]
}

@test "not inited: error on --uninstall" {
run ../transcrypt --uninstall
[ "$status" -ne 0 ]
[ "${lines[0]}" = "transcrypt: the current repository is not configured" ]
[[ "${output}" = *"transcrypt: the current repository is not configured"* ]]
}

@test "not inited: error on -u" {
run ../transcrypt -u
[ "$status" -ne 0 ]
[ "${lines[0]}" = "transcrypt: the current repository is not configured" ]
[[ "${output}" = *"transcrypt: the current repository is not configured"* ]]
}


@test "not inited: error on --upgrade" {
run ../transcrypt --upgrade
[ "$status" -ne 0 ]
[ "${lines[0]}" = "transcrypt: the current repository is not configured" ]
[[ "${output}" = *"transcrypt: the current repository is not configured"* ]]
}
10 changes: 5 additions & 5 deletions tests/test_pre_commit.bats
Original file line number Diff line number Diff line change
@@ -74,14 +74,14 @@ load "$BATS_TEST_DIRNAME/_test_helper.bash"

run "$BATS_TEST_DIRNAME"/../transcrypt --cipher=aes-256-cbc --password='abc 123' --yes
[ "$status" -eq 0 ]
[ "${lines[0]}" = "WARNING:" ]
[ "${lines[1]}" = "Cannot install Git pre-commit hook script because file already exists: .git/hooks/pre-commit" ]
[ "${lines[2]}" = "Please manually install the pre-commit script saved as: .git/hooks/pre-commit-crypt" ]
[[ "${output}" = *"WARNING:"* ]]
[[ "${output}" = *"Cannot install Git pre-commit hook script because file already exists: .git/hooks/pre-commit"* ]]
[[ "${output}" = *"Please manually install the pre-commit script saved as: .git/hooks/pre-commit-crypt"* ]]

# Confirm pre-commit-crypt file is installed, but not copied to pre-commit
run cat .git/hooks/pre-commit-crypt
[ "$status" -eq 0 ]
[ "${lines[1]}" = '# Transcrypt pre-commit hook: fail if secret file in staging lacks the magic prefix "Salted" in B64' ]
[[ "${output}" = *'# Transcrypt pre-commit hook: fail if secret file in staging lacks the magic prefix "Salted" in B64'* ]]
[ ! -s .git/hooks/pre-commit ] # Zero file size]
}

@@ -97,7 +97,7 @@ load "$BATS_TEST_DIRNAME/_test_helper.bash"

run "$BATS_TEST_DIRNAME"/../transcrypt --uninstall --yes
[ "$status" -eq 0 ]
[ "${lines[0]}" = 'WARNING: Cannot safely disable Git pre-commit hook .git/hooks/pre-commit please check it yourself' ]
[[ "${output}" = *'WARNING: Cannot safely disable Git pre-commit hook .git/hooks/pre-commit please check it yourself'* ]]
[ -f .git/hooks/pre-commit ]
[ ! -f .git/hooks/pre-commit-crypt ]
}
15 changes: 12 additions & 3 deletions transcrypt
Original file line number Diff line number Diff line change
@@ -139,7 +139,16 @@ git_clean() {
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"
# Encrypt the file to base64, ensuring it always includes the prefix 'Salted__' with the salt. #133
(
# Always prepend encrypted ciphertext with "Salted__" prefix and binary salt value
echo -n "Salted__" && echo -n "$salt" | xxd -r -p &&
# Encrypt file to binary ciphertext
ENC_PASS=$password "$openssl_path" enc -e "-${cipher}" -md MD5 -pass env:ENC_PASS -S "$salt" -in "$tempfile" |
# Strip "Salted__" prefix and salt value if also added by OpenSSL (version < 3)
LC_ALL=C sed -e "s/^\(Salted__.\{8\}\)\(.*\)/\2/"
) |
base64
fi
}

@@ -149,7 +158,7 @@ git_smudge() {
cipher=$(git config --get --local transcrypt.cipher)
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"
tee "$tempfile" | ENC_PASS=$password "$openssl_path" enc -d "-${cipher}" -md MD5 -pass env:ENC_PASS -a 2>/dev/null || cat "$tempfile"
}

git_textconv() {
@@ -161,7 +170,7 @@ git_textconv() {
cipher=$(git config --get --local transcrypt.cipher)
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"
ENC_PASS=$password "$openssl_path" enc -d "-${cipher}" -md MD5 -pass env:ENC_PASS -a -in "$filename" 2>/dev/null || cat "$filename"
}

# shellcheck disable=SC2005,SC2002,SC2181