Skip to content
NorscodeNorscode

Hash a password safely

ExampleBy the Norscode project

Argon2id from the standard library — the right tool for passwords, without a single external dependency.

Passwords should never be stored in plaintext — nor with a fast hash like SHA-256. The standard library has Argon2id, which is made precisely for this.

bruk std.argon2id som argon2

funksjon start() -> heltall {
    la passord = "et-langt-og-tilfeldig-passord"
    la salt = builtin.random_hex(16)
    la hash = argon2.hash(passord, salt)
    skriv("Lagre denne, ikke passordet: " + hash)

    hvis argon2.verify(passord, hash) {
        skriv("Passordet stemmer")
    } ellers {
        skriv("Feil passord")
    }
    returner 0
}

What happens here

You never store the password. You store the result of argon2.hash, and when the user logs in later, you run argon2.verify with what they typed against the stored value. Even with full access to your database, an attacker cannot get the passwords back out — only the ability to guess, one guess at a time.

The salt is random bytes that become unique per password. Without salt, two users with the same password would get the same hash, and an attacker could look up common passwords in a prebuilt table. With salt, each password must be attacked on its own. The builtin.random_hex function draws from a cryptographic randomness source — do not use an ordinary random generator for this.

Why Argon2id and not SHA-256

It seems backwards, but here speed is a disadvantage. SHA-256 is made to be fast, because it is meant to hash large files. That is exactly why it is terrible for passwords: an attacker with a graphics card can try billions of guesses per second.

Argon2id is made to be slow and memory-hungry on purpose. It can be tuned for how much time and memory each computation should cost. You barely notice it — the user waits a few hundred milliseconds at login — but it makes mass attacks thousands of times more expensive. Argon2id is moreover the variant that withstands both memory-tradeoff and side-channel attacks, and is the one you should choose when in doubt.

The right tool for the right job

The standard library also has BLAKE2b for ordinary hashes, and ChaCha20-Poly1305 for authenticated encryption. These are three different jobs:

  • Password hash (Argon2id): one-way, deliberately slow, for values you should never get back.
  • Ordinary hash (BLAKE2b): one-way, fast, for checksums and fingerprints.
  • Encryption (ChaCha20-Poly1305): two-way, for data you will read again later.

Never use a password hash for encryption, or vice versa. It is one of the most common and most serious mistakes in homemade security code.

Related

Back to the overview