The blog post you quote is quite imprecise in its formulation. However, by looking at the KWallet source code, especially this file (for the password hashing) and that file (for the invocation of the encryption code), we see the following:
The password is extended into a symmetric key of size 20, 40 or 56 bytes (160, 320 or 448 bits) by applying SHA-1 repeatedly. Namely:
If the password has length 0 to 16 characters, the key will have length 20 bytes and be the repeated application of SHA-1 (2000 times) on the password (the password is hashed, then the 20-byte output is hashed again, and again, for 2000 invocations of SHA-1).
If the password has length 17 to 32 characters, then the key will have length 40 bytes: the first 16 characters are processed as above, then the remaining characters are processed similarly, yielding 20 more bytes.
If the password has length 33 to 48 characters, then the key will have length 56 bytes: the first 16 characters are processed as above, the second chunk of 16 bytes of characters as well, and then the third chunk; the output for the first chunk is then truncated to 16 bytes, for a total of 56 bytes.
If the password has length 49 characters or more, then the 2000 SHA-1 invocations will happen four times. For the fourth chunk, the complete rest of the password will be used. The four 20-byte output are then each truncated to 14 bytes, and these are concatenated, yielding a 56-byte output.
As a password hashing function, it is quite poor. It is clunky and not regular. It is not salted, allowing for efficient parallel attacks, when several KWallet instances must be broken (as usual, "parallelism" also means that precomputed tables can be used, negating the slowing effect of the 2000 SHA-1 invocations). Moreover, it "splits" the password, so if an attacker finds a password hash, then he can attack each chunk independently of the others. This means that the security of the whole thing relies a lot on how well the Blowfish block cipher behaves when used as a hash function. This is, at best, a poorly studied property.
The encryption purports to use CBC, but does not. In CBC, you are supposed to encrypt a sequence of blocks (8 bytes per block with Blowfish); before encrypting a block, it is first XORed with the previous encrypted block. For the first block, we must conjure a formal "previous block" which is the Initialization Vector. CBC requires a random IV.
In the KWallet code, we see that the code indeed prepares a random IV of the right size.... then completely fails to do CBC. The call to encryption is:
int rc = bf.encrypt(wholeFile.data(), wholeFile.size());
(line 291 of backendpersisthandler.cpp
)
Looking at the implementation for this encrypt()
method, in cbc.cc
, we see that it will create a temporary buffer of the same size of the whole file; then fill it with zeros; then XOR all these zeros with the data to encrypt (which won't change the data...); then proceed to encrypt each block independently of each other. This is, indeed, ECB mode, not CBC. It is quite obvious that this is a programming error; the lesson to learn, though, is that since KWallet appears to work, then the mistake was not detected: security cannot be tested through functionality.
(This implies that the random IV which was computed does nothing here; it is encrypted by itself but does not impact any other byte in the whole file.)
ECB mode is known to be weak in the following sense: it leaks information about what blocks are equal to each other. For an uncompressed picture, this is deadly, as demonstrated with the usual penguin image. For a KWallet, this is a source of worry: the internal structure has some redundancy, and this may be exploitable, although it would require some effort to ascertain the extent of the issue.
Note that since the password is not salted, two successive versions of the KWallet protected with the same password will use the same symmetric key, so block equalities leaked by ECB apply to all successive versions of the KWallet.
There is a homemade MAC. The last 20 bytes of the file (excluding some padding) contain a SHA-1 value computed over the rest. This is, generally speaking, not a good MAC. It would be an extremely bad MAC if the encryption used RC4 or a block cipher in CTR mode. With a block cipher in ECB mode (as used here), it is not as bad, but still poor.
The whole code reeks of homemade crypto slapped together by someone who did not master the concepts. This is bad. Also, I find the code to be atrocious in many respects (e.g. when the password chunks are hashed, the loop which invokes SHA-1 repeatedly is ruthlessly duplicated; that's a shooting offence). To "improve" KWallet, I suggest deleting the whole code and starting from scratch.
It seems that the code includes some optional support for not doing the password hashing and encryption itself (as we saw, it does it very poorly), but instead using GnuPG. Now THAT is a good idea. GnuPG implements the OpenPGP format which, for all its shortcomings, is at least decent cryptographically speaking (when properly used), and GnuPG is also known to be a tolerably good implementation. To improve storage of your KWallet, see if you can convince your computer to use this GnuPG support code and format.