Password Handling Details

For the security-conscious, the way services store and handle their passwords may be of some interest. This page attempts to offer some transparency into the way the Haven & Hearth website and game service implement password storage and handling, for those thus concerned.

As a general note, whenever the below text describes choices between multiple parameters, it is possible for a programmatic client to make a choice, but (except for the Legacy option described below) there is no user-facing UI to choose anything but the default.

Password storage

Haven currently implements two main methods of password storage: Salted bcrypt hashes, or SRP verifiers. A client can choose which method of storage it wants to use, with SRP being the default.

For bcrypt storage, a cost of 12 is currently used, and the password is also pre-hashed with a selectable pre-hash algorithm before being hashed again by bcrypt; this is so that the pre-hash can be done on the client side (for clients that support it), so as to minimize the extent to which the server needs to handle the plaintext password. The pre-hashing step and its options are described below.

For SRP storage, pre-hashing is also done, this time in order to harden the verifier against dictionary attacks. SRP verifiers are intrinsically not hardened in any other way, except for SRP itself being mildly expensive. SRP is implemented in the 4096-bit group defined by RFC 5054.

Pre-hashing

For the above mentioned pre-hashing steps, the main algorithms supported are: PBKDF2, Argon2, and simple, unsalted SHA256. Excepting the latter, a per-account salt is used.

Unsalted SHA256 is mainly supported for legacy reasons, as described below. Of the stronger algorithms, PBKDF2 is supported with client-selectable costs between 216 and 224, with 220 being the default; whereas Argon2 is supported for parameters up to t=8, m=216, p=8, with the defaults being t=4, m=216, p=2. PBKDF2 is the default pre-hash algorithm.

The choices of PBKDF2 over Argon2 and of the Argon2 parameters may appear odd to some. Unfortunately, various practical considerations (including, but not limited to, that of the website implementation being in WebAssembly rather than native) severely limit the possible Argon2 parameters to those chosen; and while it was planned to become the default, it turns out that under those parameter choices, Argon2 is not obviously better than PBKDF2 for GPU- and ASIC-resistance. PBKDF2 was therefore chosen by virtue of it having well-optimized, native implementations for all relevant platforms. Other algorithms, such as Pufferfish2 are being considered.

Up until around 2024, bcrypt storage with SHA256 pre-hashing was the default, so particularly security-conscious users may want to upgrade if they have not already. Simply executing a password change (even to the same password) will always use the latest default settings.

Client authentication

The client authentication protocol and the game client itself implements the password protocols "as expected". For example, SRP is executed on a server-generated challenge, protecting against replay attacks, never exposing any password-equivalent to the wire or the server; and for bcrypt-stored passwords, the plaintext password is properly pre-hashed client-side so that, while the password pre-hash is password-equivalent for authentication, at least the plaintext password never leaves the client.

It should be specially noted in this context, that the "Remember me" option in the client does not save the password itself, but rather generates a random token that is saved on both the client and the server for future authentication. Such saved tokens can be managed on the Account Security page on the website.

Website authentication

The website does its best to also follow best practices to authenticate, but its ability to do so depends on the capabilities of the browser environment. For example, the presence of hashing functions depends on the site being loaded over TLS, and the implementation itself depends on a certain level of JavaScript standards compliance.

To the extent that all such prerequisites are met, the website executes the appropriate authentication protocol fully on the browser side, yielding the security properties expected thereof. However, if they are not entirely met, the website will silently downgrade the security and send the password in plaintext to the server, leaving the validation to it. This may leave the website somewhat vulnerable to downgrade attacks, but the current implementation prioritizes ease-of-use, so as to not bother users with technicalities if it cannot execute the authentication protocol on the browser side. There is no exhaustive list of browser prerequisites at this point, but it is expected that halfway modern browsers be capable of the full implementation, so long as the page is loaded over TLS.

Registration

When registering on the website, or setting a new password on the Account Security page, as long as the same prerequisites as for authentication (as covered above) are met, the plaintext password never leaves the client. When bcrypt storage is chosen, only the pre-hashed password is sent to the server, and when SRP storage is chosen, only the (hardened) verifier is sent to the server. In the case of bcrypt, the pre-hashed password is, of course, password-equivalent as far as authentication goes; and in the case of SRP, the verifier, while not password-equivalent, would be subject to dictionary attacks. Nonetheless, the server at least never sees the plaintext password. However, similar to the authentication phase, the website will silently downgrade to sending the plaintext password in case the browser environment prerequisites are not met.

Legacy passwords

The Legacy Haven client only supports bcrypt storage with SHA256 pre-hashing, and thus in order to play Legacy Haven, the account in question needs to have a password that is stored as such. On the profile page, therefore, it is possible to select Legacy storage when setting a password, and doing so will result in the password being stored as a bcrypt hash, with SHA256 pre-hashing.