Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions ChangeLog.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,20 @@
# Tomb ChangeLog

## Unreleased
### TBA

Special character sequences like newline (`\n`), tabfeed (`\t`) and
similar from ANSI Escape Sequences caused unexpected behaviour when
setting passwords. The safe way to pipe the passwords into `gnupg`
would go through the shell and if sequences were encountered
they would be processed.
Which brings unintended changes in the entered password. In the case
of a newline the user could end up with a much weaker password
than expected and not notice it necessarily.
With this release the password won't be changed by the shell pipe
anymore. `Pinentry` and `libassuan` still do their thing though.
For an overview see [Known Bugs](./KNOWN_BUGS.md).

## 2.13
### July 2025

Expand Down
38 changes: 38 additions & 0 deletions KNOWN_BUGS.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,41 @@
# Passwords getting silently altered
## Issues with Tomb version x.x to 2.13

The safe way of piping a password into gnupg would be interpret by the shell
and therefore character sequences like `ANSI Escape Sequences` could cause
unintended changes to the password and not necessarily be noticeable.
But also escaping characters can introduce changes to the final password.
In general a tomb created with 2.13 and before can still be unlocked, but
it needs to happen with unsafe options.
Below is a table with some examples:

| Sequence | Theoretical | Real | Unlock 2.13 | Unlock >2.13 | Notes |
|----------|-------------|------|-------------|--------------|-------|
| newline | `test\ntest` | `test` | `test` or `test\ntest` or `test\nwhatever` | `test` | Position matters greatly
| horizontal tab | `test\test` | `test<TAB>est` | `test\test` | `--tomb-pwd "test\test"` |
| formfeed | `test\ftest` | `test\xCtest` | `test\ftest` | `--tomb-pwd "test\ftest"` | dm-crypt will throw a warning |
| bell | `test\atest` | `test\x07test` | `test\atest` | `--tomb-pwd "test\atest"` | bell will appear in output
| backspace | `test\btest` | theoretically `testest`? | `test\btest` | `--tomb-pwd "test\btest"` | behaves unexpectedly
| vertical tab | `test\vtest` | `test<VTAB>test` | `test\vtest` | `--tomb-pwd "test\vtest"` |
| carriage return | `test\rtest` | `test<CR>test` | `test\rtest` | `--tomb-pwd "test\rtest"` |
| escape character (wrong) | `test\etest` | in shell `testest` | `test\etest` | `--tomb-pwd "test\etest"` | behaves unexpectedly
| escape character | `test\e[1Ktest` | in shell ` test` | `test\e[1Ktest` | `--tomb-pwd "test\e[1Ktest"` | erase from start to cursor
| escpape backslash | `testtest\` | - | - | - | created key is safely protected...

It isn't explored what happened in cases like `\ntest` or `test\`.
In the first case would `test` be discarded or end up as the `LUKS` key?
Essentially the same question for the second case:
What does the `LUKS` key look like after the password was appended with the
intended key?
The general advice is to generate a new tomb to be on the safe side.

Of note: This doesn't address the quirk with `%`s in a password.
Pinentry or rather Assuan have the requirement, that some special sequences
need to be percent escaped (`%` as `%25`, `CR` as `%0D` and `LF` as `%0A`).
If such a password was set via pinentry and is later supplied via
`--unsafe --tomb-pwd` it will need to be set as `--tomb-pwd test%25test`.


# Password bug failing to open tombs
## Issue with Tomb version 2.12 (short lived)

Expand Down
7 changes: 6 additions & 1 deletion doc/tomb.1
Original file line number Diff line number Diff line change
Expand Up @@ -384,7 +384,8 @@ the non-blocking source of Linux kernel doesn't degrades the quality
of random.
.B
.IP "--tomb-pwd <string>"
Use string as password when needed on tomb.
Use string as password when needed on tomb. Refer to Password Input
for edge cases.
.B
.IP "--tomb-old-pwd <string>"
Use string as old password when needed in tomb commands requiring
Expand Down Expand Up @@ -473,6 +474,10 @@ When using it from a remote ssh connection it might be necessary to
force use of pinentry-tty for instance by unsetting the DISPLAY (X11)
or WAYLAND_DISPLAY (Wayland) environment var.

If using \fI--tomb-pwd\fR special care must be taken with passwords that
contain what pinentry/assuan considers special sequences. One of those is
the percent symbol (\fI%\fR) which needs to be manually escaped as (\fI%25\fR).

.SH SWAP

On execution of certain commands Tomb will complain about swap memory
Expand Down
37 changes: 12 additions & 25 deletions tomb
Original file line number Diff line number Diff line change
Expand Up @@ -581,7 +581,7 @@ ask_password() {
return 1
}

print "$password"
print -R -n - "$password"
return 0
}

Expand Down Expand Up @@ -1294,12 +1294,12 @@ _load_key() {
# contains tweaks for different gpg versions
# support both symmetric and asymmetric encryption
gpg_decrypt() {
# fix for gpg 1.4.11 where the --status-* options don't work ;^/
# gpg version check necessary for <2.1.x (although those aren't supported anymore)
local gpgver=$(gpg --version --no-permission-warning | awk '/^gpg/ {print $3}')
local gpgpass="$1\n$TOMBKEY"
local gpgpass="$1"
local tmpres ret
typeset -a gpgopt
gpgpopt=(--batch --no-tty --passphrase-fd 0 --no-options)
gpgpopt=(--batch --no-tty --passphrase-fd 3 --no-options --no-mdc-warning --no-permission-warning --no-secmem-warning)

{ option_is_set -g } && {
gpgpass="$TOMBKEY"
Expand All @@ -1316,29 +1316,18 @@ gpg_decrypt() {
}
}

[[ $gpgver == "1.4.11" ]] && {
_verbose "GnuPG is version 1.4.11 - adopting status fix."
TOMBSECRET=`print - "$gpgpass" | \
gpg --decrypt ${gpgpopt[@]}`
ret=$?
unset gpgpass
return $ret
}

_tmp_create
tmpres=$TOMBTMP
TOMBSECRET=`print - "$gpgpass" | \
gpg --decrypt ${gpgpopt[@]} \
--status-fd 2 --no-mdc-warning --no-permission-warning \
--no-secmem-warning 2> $tmpres`
TOMBSECRET=`print - "$TOMBKEY" | \
gpg --decrypt ${gpgpopt[@]} --status-fd 2 \
3<<<"$gpgpass" 2> $tmpres`
unset gpgpass
ret=1
for i in ${(f)"$(cat $tmpres)"}; do
_verbose "$i"
[[ "$i" =~ "DECRYPTION_OKAY" ]] && ret=0;
done
return $ret

}


Expand Down Expand Up @@ -1860,26 +1849,24 @@ gen_key() {
fi

# Set gpg inputs and options
gpgpass="${tombpass}\n$TOMBSECRET"
gpgopt=(--passphrase-fd 0 --symmetric --no-options)
gpgopt=(--passphrase-fd 3 --symmetric --no-options)
opt='-n'
fi

_tmp_create
local tmpres=$TOMBTMP
print $opt - "$gpgpass" \
print $opt - "$TOMBSECRET" \
| gpg --openpgp --force-mdc --cipher-algo ${algo} \
--batch --no-tty ${gpgopt} \
--status-fd 2 -o - --armor 2> $tmpres >> "$1"
unset gpgpass
--batch --no-tty ${gpgopt} --status-fd 2 -o - \
--armor 3<<<"$tombpass" 2> $tmpres >> "$1"
# check result of gpg operation
for i in ${(f)"$(cat $tmpres)"}; do
_verbose "$i"
done

# print -n "${tombpass}" \
# | gpg --openpgp --force-mdc --cipher-algo ${algo} \
# --batch --no-options --no-tty --passphrase-fd 0 --status-fd 2 \
# --batch --no-options --no-tty --passphrase-fd 3 --status-fd 2 \
# -o - -c -a ${lukskey}

TOMBPASSWORD="$tombpass" # Set global variable
Expand Down
Loading