@@ -268,92 +268,68 @@ stage_rekeyed_files() {
268
268
fi
269
269
}
270
270
271
- # save helper scripts under the repository's git directory
272
- save_helper_scripts () {
273
- mkdir -p " ${GIT_DIR} /crypt"
274
-
275
- # The `decryption -> encryption` process on an unchanged file must be
276
- # deterministic for everything to work transparently. To do that, the same
277
- # salt must be used each time we encrypt the same file. An HMAC has been
278
- # proven to be a PRF, so we generate an HMAC-SHA256 for each decrypted file
279
- # (keyed with a combination of the filename and transcrypt password), and
280
- # then use the last 16 bytes of that HMAC for the file's unique salt.
281
-
282
- cat << -'EOF ' >"${GIT_DIR}/crypt/clean"
283
- #!/usr/bin/env bash
284
- filename=$1
285
- # ignore empty files
286
- if [[ -s $filename ]]; then
287
- # cache STDIN to test if it's already encrypted
288
- tempfile=$(mktemp 2>/dev/null || mktemp -t tmp)
289
- trap 'rm -f "$tempfile"' EXIT
290
- tee "$tempfile" &>/dev/null
291
- # the first bytes of an encrypted file are always "Salted" in Base64
292
- read -n 8 firstbytes <"$tempfile"
293
- if [[ $firstbytes == "U2FsdGVk" ]]; then
294
- cat "$tempfile"
295
- else
296
- cipher=$(git config --get --local transcrypt.cipher)
297
- password=$(git config --get --local transcrypt.password)
298
- salt=$(openssl dgst -hmac "${filename}:${password}" -sha256 "$filename" | tr -d '\r\n' | tail -c 16)
299
- ENC_PASS=$password openssl enc -$cipher -md MD5 -pass env:ENC_PASS -e -a -S "$salt" -in "$tempfile"
300
- fi
301
- fi
302
- EOF
303
-
304
- cat << -'EOF ' >"${GIT_DIR}/crypt/smudge"
305
- #!/usr/bin/env bash
271
+ # The `decryption -> encryption` process on an unchanged file must be
272
+ # deterministic for everything to work transparently. To do that, the same
273
+ # salt must be used each time we encrypt the same file. An HMAC has been
274
+ # proven to be a PRF, so we generate an HMAC-SHA256 for each decrypted file
275
+ # (keyed with a combination of the filename and transcrypt password), and
276
+ # then use the last 16 bytes of that HMAC for the file's unique salt.
277
+ crypt_clean () {
278
+ filename=$1
279
+ # ignore empty files
280
+ if [[ -s $filename ]]; then
281
+ # cache STDIN to test if it's already encrypted
306
282
tempfile=$( mktemp 2> /dev/null || mktemp -t tmp)
307
283
trap ' rm -f "$tempfile"' EXIT
308
- cipher=$(git config --get --local transcrypt.cipher)
309
- password=$(git config --get --local transcrypt.password)
310
- tee "$tempfile" | ENC_PASS=$password openssl enc -$cipher -md MD5 -pass env:ENC_PASS -d -a 2>/dev/null || cat "$tempfile"
311
- EOF
312
-
313
- cat << -'EOF ' >"${GIT_DIR}/crypt/textconv"
314
- #!/usr/bin/env bash
315
- filename=$1
316
- # ignore empty files
317
- if [[ -s $filename ]]; then
318
- cipher=$(git config --get --local transcrypt.cipher)
319
- password=$(git config --get --local transcrypt.password)
320
- ENC_PASS=$password openssl enc -$cipher -md MD5 -pass env:ENC_PASS -d -a -in "$filename" 2>/dev/null || cat "$filename"
284
+ tee " $tempfile " & > /dev/null
285
+ # the first bytes of an encrypted file are always "Salted" in Base64
286
+ read -r -n 8 firstbytes < " $tempfile "
287
+ if [[ $firstbytes == " U2FsdGVk" ]]; then
288
+ cat " $tempfile "
289
+ else
290
+ cipher=$( git config --get --local transcrypt.cipher)
291
+ password=$( git config --get --local transcrypt.password)
292
+ salt=$( openssl dgst -hmac " ${filename} :${password} " -sha256 " $filename " | tr -d ' \r\n' | tail -c 16)
293
+ ENC_PASS=$password openssl enc " -${cipher} " -md MD5 -pass env:ENC_PASS -e -a -S " $salt " -in " $tempfile "
321
294
fi
322
- EOF
295
+ fi
296
+ }
323
297
324
- # make scripts executable
325
- for script in {clean,smudge,textconv}; do
326
- chmod 0755 " ${GIT_DIR} /crypt/${script} "
327
- done
298
+ crypt_smudge () {
299
+ tempfile=$( mktemp 2> /dev/null || mktemp -t tmp)
300
+ trap ' rm -f "$tempfile"' EXIT
301
+ cipher=$( git config --get --local transcrypt.cipher)
302
+ password=$( git config --get --local transcrypt.password)
303
+ tee " $tempfile " | ENC_PASS=$password openssl enc " -${cipher} " -md MD5 -pass env:ENC_PASS -d -a 2> /dev/null || cat " $tempfile "
304
+ }
305
+
306
+ crypt_textconv () {
307
+ filename=$1
308
+ # ignore empty files
309
+ if [[ -s $filename ]]; then
310
+ cipher=$( git config --get --local transcrypt.cipher)
311
+ password=$( git config --get --local transcrypt.password)
312
+ ENC_PASS=$password openssl enc " -${cipher} " -md MD5 -pass env:ENC_PASS -d -a -in " $filename " 2> /dev/null || cat " $filename "
313
+ fi
328
314
}
329
315
330
316
# write the configuration to the repository's git config
331
317
save_configuration () {
332
- save_helper_scripts
318
+ # This directory is used by transcrypt as a working directory.
319
+ mkdir -p " ${GIT_DIR} /crypt"
333
320
334
321
# write the encryption info
335
322
git config transcrypt.version " $VERSION "
336
323
git config transcrypt.cipher " $cipher "
337
324
git config transcrypt.password " $password "
338
325
339
326
# write the filter settings
340
- if [[ -d $( git rev-parse --git-common-dir) ]]; then
341
- # this allows us to support multiple working trees via git-worktree
342
- # ...but the --git-common-dir flag was only added in November 2014
343
- # shellcheck disable=SC2016
344
- git config filter.crypt.clean ' "$(git rev-parse --git-common-dir)"/crypt/clean %f'
345
- # shellcheck disable=SC2016
346
- git config filter.crypt.smudge ' "$(git rev-parse --git-common-dir)"/crypt/smudge'
347
- # shellcheck disable=SC2016
348
- git config diff.crypt.textconv ' "$(git rev-parse --git-common-dir)"/crypt/textconv'
349
- else
350
- # shellcheck disable=SC2016
351
- git config filter.crypt.clean ' "$(git rev-parse --git-dir)"/crypt/clean %f'
352
- # shellcheck disable=SC2016
353
- git config filter.crypt.smudge ' "$(git rev-parse --git-dir)"/crypt/smudge'
354
- # shellcheck disable=SC2016
355
- git config diff.crypt.textconv ' "$(git rev-parse --git-dir)"/crypt/textconv'
356
- fi
327
+ # shellcheck disable=SC2016
328
+ git config filter.crypt.clean " $0 --crypt-clean %f"
329
+ # shellcheck disable=SC2016
330
+ git config filter.crypt.smudge " $0 --crypt-smudge"
331
+ # shellcheck disable=SC2016
332
+ git config diff.crypt.textconv " $0 --crypt-textconv"
357
333
git config filter.crypt.required ' true'
358
334
git config diff.crypt.cachetextconv ' true'
359
335
git config diff.crypt.binary ' true'
@@ -466,6 +442,8 @@ uninstall_transcrypt() {
466
442
clean_gitconfig
467
443
468
444
# remove helper scripts
445
+ # This is obsolete, but we should keep it to clean up these
446
+ # scripts from old versions of transcrypt.
469
447
for script in {clean,smudge,textconv}; do
470
448
[[ ! -f " ${GIT_DIR} /crypt/${script} " ]] || rm " ${GIT_DIR} /crypt/${script} "
471
449
done
@@ -800,6 +778,21 @@ while [[ "${1:-}" != '' ]]; do
800
778
--import-gpg=* )
801
779
gpg_import_file=${1#* =}
802
780
;;
781
+ --crypt-clean)
782
+ shift
783
+ crypt_clean " $1 "
784
+ exit 0
785
+ ;;
786
+ --crypt-smudge)
787
+ shift
788
+ crypt_smudge
789
+ exit 0
790
+ ;;
791
+ --crypt-textconv)
792
+ shift
793
+ crypt_textconv " $1 "
794
+ exit 0
795
+ ;;
803
796
-v | --version)
804
797
printf ' transcrypt %s\n' " $VERSION "
805
798
exit 0
0 commit comments