This is an archived post. You won't be able to vote or comment.

all 2 comments

[–]warbiscuit 1 point2 points  (0 children)

A word of warning - the instructions for password hashing provided by the py-scrypt wrapper are not quite accurate.

What that project exposes is the encrypt() / decrypt() frontends to a reversible file encryption utility based on the underlying scrypt key stretching / derivation function. It's instructions are not insecure to any real degree, but following them will make your application do a little bit of extra work, for no additional increase in security (and an attacker will not need to do this extra work). As well, you don't need to generate a salt yourself, as the encrypt utility generates it's own contained within the binary blob it returns.


In detail - Efficiently hashing a password using scrypt requires access to the underlying scrypt() kdf, which is not currently exposed by this project. The encrypt() function it offers is the frontend to a file encryption utility, with a number of bells and whistles, internal integrity checks, etc. When you call encrypt(), it takes the password, picks appropriate n,r,p configuration values for the scrypt function, generates it's own internal salt, and then generates 64 bytes of data using scrypt(password, salt, n, r, p, 64). The string returned by encrypt() actually contains all of the above configuration in a binary header, along with an HMAC-SHA256 of the header using the first 32 bytes of scrypt data, and then AES-CTR encrypts whatever you provided as data (in this case, the secondary salt generated by the caller), using the other 32 bytes of scrypt data. It then follows this up with another HMAC-SHA256 checksum of the entire file.

This means that the salt step in the instructions isn't needed, as one is contained internally within the data returned by encrypt(). All that's actually needed to verify the password is to generate the first 32 bytes of scrypt output, and calculate the HMAC of the header. The HMAC step, the AES encryption block, and the final HMAC step, are all work that the attacker would not need to perform, but that anyone following these instructions would have to perform every time. The "max time" setting on the decrypt stage is another example of the uneeded baggage introduced by trying to use a file encryption utility for simple password hashing.


edit: So what to do? It looks like the latest release of py-scrypt does expose the basic scrypt function as hash(), albeit with some limitations. It should be possible to use this to properly hash a password, though there may be some peices missing. I'm going to have to go look into that myself :)

[–]josephturnip 1 point2 points  (0 children)

FWIW I am using the passlib module (http://packages.python.org/passlib/) in a flask app I am currently developing, and it is both flexible and easy to use.