Password generation is weaker than expected
The algorithm is as follows, according to masterpassword-algorithm.pdf
:
masterKey = SCRYPT( key, seed, N, r, p, dkLen )
key = <master password>
seed = scope2 . LEN(<name>) . <name>
N = 32768
r = 8
p = 2
dkLen = 64
-----
siteKey = HMAC-SHA-256( key, seed )
key = <master key>
seed = scope3 . LEN(<site name>) . <site name> . <counter>
-----
template = templates[ <site key>[0] % LEN( templates ) ]
for i in 0..LEN( template )
passChars = templateChars[ template[i] ]
passWord[i] = passChars[ <site key>[i+1] % LEN( passChars ) ]
After reviewing this, I found the following flaws:
-
Medium: no per-site info goes into SCRYPT. Thus once SHA256 is broken enough (not the case yet), an attacker may find out the key. SCRYPT does not protect sites from each other - it only protects the master password itself (e.g. from dictionary attacks)! A successful attack to recover masterKey would still require multiple sites to cooperate, as well (or one site having seen multiple passwords).
-
Minor: uneven distribution of passwords. Not only does site_key consist of bytes and thus the modulo operation causes uneven distributions (unless LEN(...) is always a power of two), the templates also differ in entropy contained.
I consider the former flaw a rather important issue, as it may greatly impact security in a few years (or a decade). Luckily we've got Bitcoin as a kinda "canary' for SHA256 security :) The latter is probably OK, but it would be worth providing a calculated number describing the entropy of generated passwords despite this (it's likely still high enough).