# RFC: Argon2 support from sodium

- Status: Implemented (PHP 7.4)
- Authors: Sara Golemon, pollita@php.net
- Date: 2019-04-05
- Version: 0.1
- Original: https://wiki.php.net/rfc/sodium.argon.hash
- Page: https://externals.io/rfc/sodium.argon.hash
- More for agents: search with https://externals.io/search.md?q={query} · RFCs at https://externals.io/rfc.md · JSON API at https://externals.io/api · documentation at https://externals.io/llms.txt

## Votes

### Provide argon2i(d) from ext/sodium when argon not present (closed)

Yes: 30 · No: 0

Voters: ashnazg (Yes), carusogabriel (Yes), cpriest (Yes), daverandom (Yes), derick (Yes), duncan3dc (Yes), emir (Yes), galvao (Yes), gasolwu (Yes), girgias (Yes), jasny (Yes), jedisct1 (Yes), jhdxr (Yes), jpauli (Yes), kelunik (Yes), kguest (Yes), mariano (Yes), mike (Yes), narf (Yes), nikic (Yes), ocramius (Yes), petk (Yes), pollita (Yes), ramsey (Yes), remi (Yes), reywob (Yes), rjhdby (Yes), salathe (Yes), sergey (Yes), stas (Yes)

## Discussions on the mailing list

- [\[RFC\] Provide argon2 support for password_hash() from ext/sodium](https://externals.io/message/105115.md) — started on 2019-04-05, 4 messages
- [libsodium based Argon2i(d) password_hash()](https://externals.io/message/105991.md) — started on 2019-06-19, 3 messages
- [\[RFC\]\[VOTE\] Argon2i(d) password_hash() via ext/sodium](https://externals.io/message/106047.md) — started on 2019-06-23, 2 messages

---

## Introduction

If PHP core was built without libargon, then password\_hash() and family will not support the argon2i and argon2id hashing mechanisms. Since [Password Hash Registry](https://externals.io/rfc/password_registry) (implemented in 7.4) allows dynamically loaded extensions to register additional algorithms at load time, and since libsodium implements the argon2i and argon2id algorithms, it makes sense to provide backfill implementations of these algorithms if core lacks them.

For anyone who builds PHP themselves, this is mostly a non-issue as they can install libargon before compiling PHP. For distributions, however, this allows the core PHP package to be leaner with fewer external dependencies, while still providing improved algorithm support for those who need it.

## Proposal

Wrap crypto\_pwhash\_str\_alg() and crypto\_pwhash\_str\_verify() from libsodium to provide argon2i and argonid implementations to the password\_hash() family of functions if core has not already registered these algorithms.

### Additional Changes

PHP's default tuning for the libargon based Argon2i(d) hashing mechanisms hasn't been updated in awhile and is a bit low for best practices. Because of this, PHP's defaults for libargon usage will be updated to match libsodium's OPSLIMIT\_MODERATE and MEMLIMIT\_MODERATE current values. Defaults for sodium implementation of argon2i(d) will also use these hardcoded values rather than constants in order to ensure consistency between builds of the same PHP version.

- *mem\_cost* default: **256 \* 1024** KB (libargon takes values in KB, so the user-facing API is normalized to KB. For libsodium, we transparently multiply by 1024 since it expects bytes)
- *time\_cost* default: **3**
- *threads* default: **1** (libsodium has a max threads count of 1)

### New Constants

Just in case an application wants to know where their argon2 support is coming from, I'd propose a new constant to be declared by whichever module is providing the support.

PASSWORD\_ARGON2\_PROVIDER == 'standard' \|\| 'sodium'

## Backward Incompatible Changes

- **Incompatibilities between libargon and libsodium:** Sodium's argon2 implementation enforces a minimum *time\_cost* value of **3**. Prior to PHP 7.4, the default value for *time\_cost* was **2**. This means that argon2 password hashes produced using password\_hash() on earlier versions of PHP (and using the default cost value) will not be verifiable by the ext/sodium implementation of these algorithms. Indeed, any argon2 password hash produced using an explicit *time\_cost* of 2 or less will fail to verify with the libsodium implementation.
    - Note that for installations which explicitly provide libargon support, this presents no change in behavior, as the libargon implementation in ext/standard supersedes the sodium implementation.
    - The above turned out to be incorrect. While libsodium will refuse to generate hashes with a time\_cost &lt; 3, it will happily verify them.
- **libsodium support for explicitly choosing algorithm:** libsodium &gt;= 1.0.15 provides an API for explicitly choosing which argon2 algorithm to use. Older versions of libsodium make this decision for you. For example, my build using libsodium 1.0.13 always produces argon2i hashes, not argon2id. Options: 
    - Make libsodium &gt;= 1.0.15 a requirement for building
    - Make libsodium &gt;= 1.0.15 a requirement for including password\_hash() support, but still building other features (preferred option)
    - Simply accept not having all algorithms available. (Worst option IMO) 
        - This RFC will be moving forward with the second option above: Only export argon2i/argon2id password hashing functions which libsodium &gt;= 1.0.15 is available
- **libsodium with threads &gt; 1**: libsodium's pwhash function does not accept a *threads* parameter and uses a hard-coded value of **1**. PHP's password\_hash() wrapping of this implementation will fail closed with an error if a value greater than one is specified.

## Proposed PHP Version(s)

7.4

## Vote

Started 23rd June 2019. Ends 7th July 2019

**Vote: Provide argon2i(d) from ext/sodium when argon not present** — Yes: 30 · No: 0 (closed)

## Proposed Patch

\* <https://github.com/php/php-src/pull/4012> This implementation only registers the algos for password\_hash() \*IF\* the libsodium library is recent enough. (preferred option umder BC Implications)
