[pkg-cryptsetup-devel] Bug#763294: cryptsetup: askpass should implement keyboard randomisation as a countermeasure to keyloggers

Christoph Anton Mitterer calestyo at scientia.net
Sun Sep 28 21:05:21 UTC 2014


Package: cryptsetup
Version: 2:1.6.6-1
Severity: wishlist


Hey.

A nice feature for askpass would be a trivial but effective measure
against keyloggers.


The applications should randomly permute the mapping of keys every time
a password is queried and display the mapping from the characters/keys,
pressed on the input device, to those which are actually used in the
password.

An example would be this.
> Key mappings:
>   character used for the password: ABCDEF0123456789$/;
>   character pressed on the device: ;E48AD05F29$7C/61B3
> Please enter your passpharse:

Of course one would need to extend this to all usable characters.
Pheraps the number of valid input characters should be configurable,
i.e. that the user specifies which keyboardlayout is used and the valid
characters are automatically deduced from that and/or that the user can
give a textfile, which simply contains all the valid passphrase
characters.

Further, the randomisation MUST take place each time the passphrase is
requested, so it should not only happen once per session or once the
system boots,... and especially it should also happen on each retry!
If not, it might again be possible for an attacker that has a keylogger
in place to make statistical attacks.

And it should be asserted, that only high quality entropy is used for
the randomisation, especially since much of these password queries may
happen during boot (e.g. dm-crypt) and urandom may not yet be well
enough sed.
If /dev/random blocks, than askpass should really print a message that
the user should generate entropy, just as e.g. gnupg does during key
generation.


Now what's the benefit from all this?
Even if an attacker has a hardware (or software) keylogger in place, he
won't know the random mapping of the keys.
So he only logs the length of the password and the statistical
distribution of the keys - if the password is well enough, the latter
shouldn't matter and there isn't much that can be done against the
former[0].

This is especially handy in scenarios like this: Using a gpg encrypted
key for dm-crypt/LUKS.
If the attacker can log the passphrase, it's useless to him since a)
it's randomised and b) he doesn't automatically have the gpg-encrypted
key.
And even if he get's the gpg-encrypted key, he still only has a
passphrase which was valid only once for that specific mapping.

The downside is of course, that it takes longer for a user to enter his
passphrase, but since the whole thing should be just optional, it
doesn't really matter.


[0] Well there is one way around that, which could be implemented as a
further option:
To ignore any additional characters at the end of the passphrase, e.g.
if we have the mappings from the example from above, and the real
password would be:
AFFE123
the user would need to enter:
;DDA5F2
but could also enter
;DDA5F2ajdk
or
;DDA5F2sijk2jrlsdf
or
;DDA5F2394573021xkkglAlf

The downside of course is, that either askpass would need to know the
correct length of the passphrase in order to throw away the rest, or
that the program (e.g. a keyscript or cryptsetup itself) where it feeds
the passphrase into, also supports ignoring the extra characters.
But the later doesn't really work with cryptsetup since the passphrase
lengths are not know, so the correct length would need to be given.
This may be done in a separate random mapping step though, e.g.
actual: 0123456789_
   key: 4_860392157
Enter the password length:

A user could now enter something like:
272735
askpass should only take everything up to excluding the first occurrence
of "_" (which is the key 2 in the above mapping) as the real length, so
in the above example
2 would map to 7
7 would already be the first "_" and everything afterwards is ignored.
So the length of the password would be 7 (which is just the length of
the above "AFFE123".

The trick with the additional 72734 and the "ignore everything after the
first _" is to prevent that the attacker can find out how many digits
the length of the passphrase has.
With:
2
alone, he'd know that the length is something between [0; 9], which may
already help a lot in brute force or statistical attacks
But with
272735
he only knows that the length is something between [0; 999999], which
doesn't really help anymore.



Cheers,
Chris.


btw: I've reported the same idea for systemd's systemd-ask-password(1),
even though I mainly planned it for cryptsetup at first.

But maybe code can be shared with them, or perhaps askpass may in the
future rely or be replaced by systemd-ask-password.
Right now I guess this i not yet possible, since system isn't the only
init system in Debian, and it's not used during the initramfs.
And there are keyscripts, like my own secure version of the the insecure
OpenPGP-keyscript in cryptsetup, which depend on askpass.



More information about the pkg-cryptsetup-devel mailing list