Geralt
  • Introduction
  • Random data
  • Constant time
  • Secure memory
  • Encoding
  • Padding
  • Hashing
  • Message authentication
  • Password hashing
  • Key derivation
  • Authenticated encryption
    • Stream and file encryption
    • AEGIS-128L
    • AEGIS-256
    • ChaCha20-Poly1305
    • XChaCha20-Poly1305
  • Key exchange
  • Digital signatures
  • Advanced
    • Validation
    • Concat
    • ChaCha20
    • XChaCha20
    • HChaCha20
    • Poly1305
    • Ed25519 to X25519
Powered by GitBook
On this page
  • Purpose
  • Usage
  • DeriveKey
  • ComputeHash
  • VerifyHash
  • NeedsRehash
  • Constants
  • Notes

Password hashing

Last updated 6 months ago

Purpose

is a memory-hard password hashing and password-based key derivation function (KDF). It takes the following parameters:

  • A password.

  • A 128-bit salt.

  • An iteration count.

  • A memory size in bytes.

  1. Set the iteration count to 3.

  2. Set the memory size as high as possible (minimum of 64 MiB) for a reasonable delay (e.g. 100 ms to 1 sec) on the type of device your application will run on.

  3. If the delay is lower than you would like, increase the iterations.

See the for some example parameters.

Usage

DeriveKey

Fills a span with output keying material computed from a password, a salt, an iteration count, and a memory size in bytes.

Argon2id.DeriveKey(Span<byte> outputKeyingMaterial, ReadOnlySpan<byte> password, ReadOnlySpan<byte> salt, int iterations, int memorySize)

Exceptions

outputKeyingMaterial has a length less than MinKeySize.

salt has a length not equal to SaltSize.

iterations is less than MinIterations.

memorySize is less than MinMemorySize.

Insufficient memory to perform key derivation.

ComputeHash

Fills a span with an encoded password hash computed from a password, a randomly generated salt, an iteration count, and a memory size in bytes.

Argon2id.ComputeHash(Span<byte> hash, ReadOnlySpan<byte> password, int iterations, int memorySize)

hash must be a fixed length due to libsodium's API, which pads the potentially variable-length output with null characters.

Exceptions

hash has a length not equal to MaxHashSize.

iterations is less than MinIterations.

memorySize is less than MinMemorySize.

Insufficient memory to perform password hashing.

VerifyHash

Verifies that an encoded password hash is correct for a given password. It returns true if the hash is valid and false otherwise.

Argon2id.VerifyHash(ReadOnlySpan<byte> hash, ReadOnlySpan<byte> password)

Exceptions

hash has a length less than MinHashSize or greater than MaxHashSize.

Invalid encoded password hash prefix.

NeedsRehash

Determines if an encoded password hash matches the expected iteration count and memory size. It returns true if the hash does not match and false if the hash matches.

Argon2id.NeedsRehash(ReadOnlySpan<byte> hash, int iterations, int memorySize)

Exceptions

hash has a length less than MinHashSize or greater than MaxHashSize.

iterations is less than MinIterations.

memorySize is less than MinMemorySize.

Invalid encoded password hash.

Constants

These are used for validation and/or save you defining your own constants.

public const int KeySize = 32;
public const int SaltSize = 16;
public const int MinKeySize = 16;
public const int MinIterations = 1;
public const int MinMemorySize = 8192;
public const int MinHashSize = 93;
public const int MaxHashSize = 128;

Notes

  • Interactive scenario (e.g. online login): 50-250 ms.

  • Semi-interactive scenario (e.g. file encryption): 250-1000 ms.

  • Non-interactive (e.g. disk encryption): 1000-5000 ms.

Here are some example parameters for different scenarios:

Source
Iterations
Memory (bytes)
*Delay (ms)

libsodium's interactive

2

67108864​

51

RFC second recommended option

3

67108864​

72

libsodium's moderate

3

268435456

314

libsodium's sensitive

4

1073741824

1745

More memory is better than more iterations. However, you will need to increase the iterations in most cases because there should be a limit on how much memory your application uses.

The parallelism is always 1 for deriving keys/hashes in libsodium. However, hashes with a parallelism greater than 1 can be verified.

You can convert the hash into a string for storage in a database using . Any null characters at the end can either be left alone or removed. Only this hash needs to be stored as the cost parameters and salt are encoded.

The best defence against password cracking will always be to use strong passwords. For example, with 6+ words.

*These delays are for my desktop (a gaming PC). You should perform benchmarks on a typical device for your application using .

Too high of an iteration count/memory size on a server could lead to denial-of-service (DoS) attacks. You can do client-side password hashing as well as server-side password hashing to help, sometimes called .

Libsodium also supports Argon2i, which is more side-channel resistant but less GPU resistant. However, Geralt only supports Argon2id because it is the and variant in the RFC plus there are against Argon2i.

Argon2id
random
Notes
random
ArgumentOutOfRangeException
ArgumentOutOfRangeException
ArgumentOutOfRangeException
ArgumentOutOfRangeException
InsufficientMemoryException
Encoding.UTF8.GetString()
ArgumentOutOfRangeException
ArgumentOutOfRangeException
ArgumentOutOfRangeException
InsufficientMemoryException
ArgumentOutOfRangeException
FormatException
ArgumentOutOfRangeException
ArgumentOutOfRangeException
ArgumentOutOfRangeException
FormatException
diceware
BenchmarkArgon2.NET
server relief
mandatory
recommended
attacks