Hi all,

We are using QLineEdit (and QML equivalent) all over KDE for passwords. This 
is an issue for types of attacks that extract raw process memory because the 
passwords can be leaked.

QLineEdit stores the current value as plain text in a QString. Which means 
that while the password entry is shown in the screen, the password is stored 
in memory for all to see (problem 1).

When the QLineEdit is destroyed, so is the QString. But, while the data buffer 
is 'deleted', its contents remain in memory until some other dynamically 
allocated object is created in the same memory space and overwrites the data - 
this is because QString does not zero-out its buffer on destruction. This 
means that the passwords remain in memory for much longer than needed (problem 
2).

Because of string reallocation on resizing, it is quite possible that, while 
the user is typing the password, that the string will be resized/reallocated 
at least once. This means that partial passwords (data from the buffer in the 
string before reallocation which is not zeroed-out) will remain in memory 
until something else overwrites them (problem 3).

All this memory can end up written to the hdd/ssd if the application is moved 
to swap by the OS (problem 4).

Transporting passwords via DBus (KWallet) is the problem 5 (guessing there's 
no need to explain this one in more detail).


Potential solutions:

Problem 2 is easily solved in Qt by having QLineEdit zero-out the string data 
on destruction if the line edit is used as a password entry. I've submitted a 
patch for this [1]. Another additional change that can be applied to QLineEdit 
is to call QString::reserve(50-or-something) when the line edit is used as a 
password field to minimize the possibility of problem 3 occurring for most 
use-cases.

Other problems are more difficult to solve. They need a custom component (from 
what I can tell).

Namely, the least a proper password entry component could do is to use a 
custom QString-like class which zeroes-out buffers before deleting them (on 
reallocation and destruction), and which tells the OS that the value contents 
should never be swapped. There is a class in QCA that can be used for this 
(SecureArray, based on botan::SecureVector).

Having a password entry component that uses a secure buffer like SecureArray 
would minimize the time the entered password is in memory to only while the 
component is shown (problem 1).

The only remaining problems are 1 and 5.

Problem 1 can not be completely solved. If the password data is kept in memory 
encrypted, the key for decryption needs to also be somewhere so that the 
program can get the actual password instead of the encrypted version.

Still, it would be an improvement over the current situation because the 
encryption password would be some random array of bytes, and the encrypted 
passwords would appear as random arrays of bytes (when encryption is good, 
encrypted data looks random). Which means that any attacks with the aim of 
extracting the password data couldn't be based on text-processing - they would 
need quite some effort of analyzing memory layout to find both the key and the 
password in order to decrypt it.


Now comes the most interesting part (IMO). which solves problem 5 and also 
influences the previous issue of having the decryption key in memory.

We can use a stream cipher to encrypt the password in memory. This means that 
the password characters can be encrypted one by one as the user types them in 
- no need to have the whole password unencrypted in memory at any point in 
time during password entry.

If we use public/private key encryption, where the password entry is in one 
process, and the password usage is in another, only the password usage process 
will be able to decrypt the password (and, again, there will be no need to the 
whole password to be decrypted at once - just one character at a time can be 
sufficient in many use-cases). This means that the attacker will need to have 
either access to the memory spaces of both processes, or to hit a very narrow 
window in the 'usage process' between 'I got the password' and 'I used the 
password and zeroed-out the data'.

The pub/priv key exchange can be done mostly securely using Diffie-Hellman 
protocol similar to what the Secret Service API [2] does. The only attack 
vector would be to replace the normal dbus server with a malicious one. In 
that case (having a malicious system component), I'd say the systems is 
already compromised and that we can not do anything to protect the user.


Thoughts?


Cheers,
Ivan

[1] https://codereview.qt-project.org/#/c/242202/
[2] https://specifications.freedesktop.org/secret-service/index.html



dr Ivan Čukić
KDE, ivan.cu...@kde.org, https://cukic.co/
gpg key fingerprint: 8FE4 D32F 7061 EA9C 8232  07AE 01C6 CE2B FF04 1C12



Reply via email to