KDE 4.12 comes with a KWallet GnuPG backend, which is more secure. More info here, including how to move existing wallets.
(Note: Tom Leek has written a more detailed analysis on StackExchange.)
I started using KWallet a few months ago to stop reusing same passwords on multiple sites. Using KDE Wallet plugin for Firefox, I setup my passwords to be automatically stored in a KWallet file, which was the best solution I found for Firefox on Linux (other than Lastpass, but it stores passwords remotely and is closed source, which I don’t prefer when dealing with passwords). But I needed access to my passwords on my Android device occasionally, so I started to work on a Python script to read KWallet .kwl files. While I was writing the script, I discovered that KWallet has some implementation problems.
About KWallet Code
The backend code for KWallet was written nearly a decade ago, from looking at the copyright notices on files. The source code for KWallet is available as part of KDE Runtime here. The backend code uses its own Blowfish and CBC implementation. KWallet’s Blowfish implementation doesn’t match the OpenSSL’s Blowfish due to wrong endianness.
The KWallet format
KWallet has a simple storage format, the data structures are stored in a serialized format using QDataStream, which is like JSON for C++/Qt. QDataStream provides a platform independent way to read and write to files, which is good since KDE runs on a variety of platforms. The serialized string generated by QDataStream is then encrypted with Blowfish in CBC mode with a key size depending on the size of the password used for the wallet given by the user.
Where things go wrong
KWallet doesn’t use the password input by the user to encrypt a wallet directly, instead it uses a key generation scheme. The key generation can be described as – break up user password into blocks of 16 characters each, and apply SHA1 2000 times on each of them. This is key stretching without a salt. These blocks are then trimmed and concatenated to fit into 56 bytes, the maximum key length allowed by the Blowfish cipher. The problem here is that the user password is not salted, so for short passwords, it’s easy to compute rainbow tables using the key generation sequence and crack multiple KWallet passwords.
Mode of cipher
KWallet uses CBC, or to be accurate, it pretends to – the keysize used for CBC is the length of the string to be encrypted, which turns CBC into the less safe mode of cipher – ECB. ECB doesn’t hide information well, for example (as on Wikipedia), an image of Tux encrypted with ECB will show patterns of the data that was encrypted:
Now, no one is going to store images in KWallet, which is when ECB is glaringly insecure, but any sort of repetitive data or reused passwords will show up in an analysis of a KWallet file. CBC and ECB mode both ensure confidentiality, but additionally CBC mode also adds randomness which ECB doesn’t.
Because KWallet effectively uses ECB, a block size of 8 would be very bad at hiding information. In most cases, there’s not even 8 bytes of information in a block in KWallet. KWallet uses QDataStream, which encodes QString objects (used in KWallet maps) as UTF-16. So, the string “abcd” will be stored as “\0a\0b\0c\0d“, which gives four bytes of information per block.
A replacement of KWallet, KSecretService has been due for a while. It even made it in release of KDE 4.8, but was removed due to a feature freeze in KDE libs. The replacement will be a part of KDE Frameworks 5, which is nearly a year away.
Unless Blowfish is broken, passwords in KWallet are safe – they just aren’t using recommended cryptography protocols. That said, if you are really *paranoid* I’d suggest the following safe practices for using KWallet to better hide information:
- Obviously, don’t reuse passwords but with KWallet using ECB necessitates it more.
- Don’t put KWallet files in version control
- Use a long password – the longer the password, lesser is KWallet susceptible to rainbow tables (or even brute force)
Huge thanks to the Matasano Crypto challenges, I learnt a lot solving those challenges.
I reported this to email@example.com on 2013-06-07, but I never heard back and later posted this on my blog. There’s a related CVE-2013-7252 for this security issue now.