Delving the depths of computing,
hoping not to get eaten by a wumpus

By Timm Murray <tmurray@wumpus-cave.net>

Castellated: An Adaptable, Robust Password Storage System for Node.js

2020-05-11


If you ask for advice on how to store passwords, you’ll get some responses that are sensible enough. Don’t roll your own crypto. Salted hashes aren’t good enough against GPU attacks. Use a function with a configurable parameter that causes exponential growth in computation, like bcrypt. If the posters are real go-getters that day, they might even bring up timing attacks.

This is fine advice as far as it goes, but I think it’s missing a big picture item: the advice has changed a number of times over the years, and we’re probably not at the final answer yet. When people see the current standard advice, they tend to write systems that can’t be easily changed. This is part of the reason why you still have companies using crypt() or unsalted MD5 for their passwords, approaches that are two or three generations of advice out of date. Someone has to flag it and then spend the effort needed for a migration. Having run such a migration myself, I’ve seen it reveal some thorny internal issues along the way.

Consider these situations:

Castellated is an approach for Node.js, written in Typescript, that allows password storage to be easily migrated to new methods. Out of the box, it supports encoding in argon2, bcrypt, scrypt, and plaintext (which is there mostly to assist testing). A password encoded this way will look something like this:

ca571e-v1-bcrypt-10-$2b$10$wOWIkiks.tbbftwkJ81BNeuOtq631SzbsVOO7VAHf5ziH.edAAqJi

This stores the encryption type, its parameters, and the encoded string. We pull this string out of a database, check that the user’s password matches, and then see if the encoding is the preferred type. Arguments (such as the cost parameter) are also checked. If these factors don’t match up, then we reencode the password with the new preferred types and store the result. This means that every time a user logs in (meaning we have the plaintext password available to us), the system automatically switches over to the preferred type.

There is also a fallback method which will help in migrating existing systems.

All matching is done using a linear-time algorithm to prevent timing attacks.

It’s all up on npm now.



Copyright © 2024 Timm Murray
CC BY-NC

Email: tmurray@wumpus-cave.net

Opinions expressed are solely my own and do not express the views or opinions of my employer.