Password generation is weaker than expected
The algorithm is as follows, according to
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> % 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).