Skip to content

Argon2id passwords

Argon2id hashes passwords into self-contained PHC strings. The PHC value contains the algorithm, version, costs, salt and derived hash. Store the complete string unchanged and pass it back to the verification native on login.

Both operations run on a worker pool. A native returning true means the job was accepted, not that hashing or verification has completed. A false return produces no callback.

Hash, then verify

#include <a_samp>
#include <crypto>

forward OnPasswordHashed(status, const hash[], context);
forward OnPasswordVerified(status, bool:matches, context);

public OnFilterScriptInit()
{
    if (!crypto_argon2id_hash("example password", "OnPasswordHashed", 42))
    {
        print("Password hashing was not queued.");
    }
    return 1;
}

public OnPasswordHashed(status, const hash[], context)
{
    if (status != CRYPTO_PASSWORD_OK)
    {
        printf("Password hashing failed (status %d).", status);
        return 1;
    }
    // Save the complete PHC string to your database. This demo verifies it now.
    if (!crypto_argon2id_verify("example password", hash, "OnPasswordVerified", context))
    {
        print("Password verification was not queued.");
    }
    return 1;
}

public OnPasswordVerified(status, bool:matches, context)
{
    printf("Verification: status=%d, matches=%d, context=%d", status, matches, context);
    return 1;
}

The integer context is passed unchanged, with a default of zero. Use it to identify an outstanding request. In a login system, validate the player's current session before applying a callback result: a reused player ID does not identify the original connection. Script unload protection is separate from player-session tracking.

Results

Status Hash callback Verify callback
CRYPTO_PASSWORD_OK hash contains the PHC string. matches says whether the password is correct.
CRYPTO_PASSWORD_INVALID_HASH Not used for generation. Invalid, unsupported or excessive-cost stored PHC; matches is false.
CRYPTO_PASSWORD_FAILED Hashing/worker failure; hash is empty. Worker failure; matches is false.

A wrong password is a completed verification: status is CRYPTO_PASSWORD_OK, with matches = false. Check both fields.

Use an array of CRYPTO_ARGON2ID_HASH_SIZE cells if copying a generated hash from the callback; this capacity includes its null terminator. Copy callback strings before returning when you need them later.

Parameters and limits

Generation currently uses fixed defaults:

Setting Value
Algorithm and version Argon2id v19.
Memory cost 19456 KiB.
Iterations 2.
Lanes 1.
Salt 16 OS-random bytes, freshly generated per hash.
Derived output 32 bytes, encoded inside the PHC string.

The API does not expose tuning parameters. Verification reads parameters from the stored PHC string, so it can verify other Argon2id v19 settings within its limits. Argon2i, Argon2d, other versions, malformed PHC strings and excessive costs produce CRYPTO_PASSWORD_INVALID_HASH.

Resource Limit
Password input 1024 bytes.
Stored PHC input 256 bytes.
Total pending operations 128, including queued, running and undelivered results.
Workers Up to 2.
Verification memory cost Up to 65536 KiB.
Verification iterations Up to 10.
Verification lanes Up to 4.

Overlong input is refused immediately. A bounded queue can also refuse work; keep application retry behavior bounded. Password bytes are preserved without text conversion, packed strings work, and an empty password is accepted by the primitive. Any password policy belongs to the application.

Callbacks and script lifetime

The named public must exist in the calling AMX when submitting. Results go to that script only, even if another script defines a public with the same name. Delivery uses rust-samp's main-thread queue and exec_public!, without retaining a mutable plugin borrow across the callback. Callbacks may submit new work.

Completion order is not guaranteed. Unloading a script invalidates its queued callbacks; reloading an AMX at the same address does not revive them. Queued work for that script is skipped; already-running calculations can finish, with their results discarded. Plugin unload cancels queued jobs, joins active workers and drops queued deliveries before the library is released.

The SDK drains deliveries with a 2 ms per-tick budget. A single callback is not interrupted by that budget, so keep callback work short. See errors and the API reference.