Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RFC is no longer a draft (RFC9106); default parameter choice out of date #101

Closed
B-McDonnell opened this issue Sep 18, 2021 · 4 comments · Fixed by #110
Closed

RFC is no longer a draft (RFC9106); default parameter choice out of date #101

B-McDonnell opened this issue Sep 18, 2021 · 4 comments · Fixed by #110

Comments

@B-McDonnell
Copy link
Contributor

B-McDonnell commented Sep 18, 2021

Argon2 now has an official informational RFC, not just a draft: RFC 9106. This change occurred on September 7th.

The previous RFC draft is referenced in two locations:

  1. PasswordHasher's docstring
  2. The "Parameters" documentation

and default parameters (no longer in line with the RFC) are implemented in PasswordHasher.

I believe the parameter choice changes were made in #41 in 2018. Since then, the draft went through revisions 4 through 13 before being marked as done. Since then, the Parameter Choice section has changed (diff here).

The RFC now recommends the following:

  1. If a uniformly safe option that is not tailored to your
    application or hardware is acceptable, select Argon2id with t=1
    iteration, p=4 lanes, m=2^(21) (2 GiB of RAM), 128-bit salt, and
    256-bit tag size. This is the FIRST RECOMMENDED option.

  2. If much less memory is available, a uniformly safe option is
    Argon2id with t=3 iterations, p=4 lanes, m=2^(16) (64 MiB of
    RAM), 128-bit salt, and 256-bit tag size. This is the SECOND
    RECOMMENDED option.

  3. Otherwise, start with selecting the type y. If you do not know
    the difference between the types or you consider side-channel
    attacks to be a viable threat, choose Argon2id.

  4. Select p=4 lanes.

  5. Figure out the maximum amount of memory that each call can
    afford and translate it to the parameter m.

  6. Figure out the maximum amount of time (in seconds) that each
    call can afford.

  7. Select the salt length. A length of 128 bits is sufficient for
    all applications but can be reduced to 64 bits in the case of
    space constraints.

  8. Select the tag length. A length of 128 bits is sufficient for
    most applications, including key derivation. If longer keys are
    needed, select longer tags.

  9. If side-channel attacks are a viable threat or if you're
    uncertain, enable the memory-wiping option in the library call.

  10. Run the scheme of type y, memory m, and p lanes using a
    different number of passes t. Figure out the maximum t such
    that the running time does not exceed the affordable time. If
    it even exceeds for t = 1, reduce m accordingly.

  11. Use Argon2 with determined values m, p, and t.

Major changes:

  1. There are now two recommended general use options for different memory requirements.
  2. Four lanes instead of twice the number of dedicated cores.
  3. There is no longer a recommendation for the maximum memory.
  4. There is no longer a recommendation for the maximum time.
  5. The RFC references the memory-wiping function for side-channel attack mitigation.

argon-cffi's parameter choice should be updated to reflect the official RFC and documentation should be updated.

Currently, the default parameters are as follows:

DEFAULT_RANDOM_SALT_LENGTH = 16
DEFAULT_HASH_LENGTH = 16
DEFAULT_TIME_COST = 2
DEFAULT_MEMORY_COST = 102400
DEFAULT_PARALLELISM = 8

They should be adapted to one of the recommended general use options:

# Default (high memory use)
DEFAULT_RANDOM_SALT_LENGTH = 16    # 128-bit salt
DEFAULT_HASH_LENGTH = 32           # 256-bit tag size
DEFAULT_TIME_COST = 1              # t = 1 iteration
DEFAULT_MEMORY_COST = 2097152      # m=2^(21) (2 GiB of RAM)
DEFAULT_PARALLELISM = 4            # p = 4 lanes

# Low memory use
DEFAULT_RANDOM_SALT_LENGTH = 16    # 128-bit salt
DEFAULT_HASH_LENGTH = 32           # 256-bit tag size
DEFAULT_TIME_COST = 3              # t = 3 iterations
DEFAULT_MEMORY_COST = 65536        # m=2^(16) (64 MiB of RAM)
DEFAULT_PARALLELISM = 4            # p = 4 lanes

It may also be useful to set some flag for which set of default parameters may be preferred.

Finally, having a utility to automatically find t given the other parameters, as per the following:

  1. Run the scheme of type y, memory m, and p lanes using a
    different number of passes t. Figure out the maximum t such
    that the running time does not exceed the affordable time. If
    it even exceeds for t = 1, reduce m accordingly.

It's time for everyone to make good use of check_needs_rehash!

@B-McDonnell
Copy link
Contributor Author

It may also be useful to set some flag for which set of default parameters may be preferred.

Some possible implementations:

  1. Boolean reduced_memory. Causes defaults to be overwritten by reduced memory defaults.
  2. Passing a parameter object. Could be part of the constructor and override defaults or separate from constructor as a class method:
    class PasswordHasher:
        ...
        @classmethod
        def with_default_parameters(cls, parameters: Parameters) -> PasswordHasher:
            # note: DefaultParameters and LowMemoryDefeaultParameters objects
            # would need to be defined elsewhere
            return PasswordHasher(
                time_cost=parameter.time_cost,
                ...
            )
    (This isn't a complete implementation, as it doesn't allow for parameter override --- just a proof of concept)
  3. LowMemoryPasswordHasher child class.

@hynek
Copy link
Owner

hynek commented Oct 28, 2021

Hi Brendan, sorry for the long silence. When you opened this issue I was traveling (!!!!) and I've been procrastinating on a release ever since because it's a big topic.

I think the best way forward is making the low-mem case the default and allow to create hashers from Parameters as per your option 2.

It was so clear that they had to publish the final version a few days after I published a basically non-release. 🤪

@B-McDonnell
Copy link
Contributor Author

I think the best way forward is making the low-mem case the default and allow to create hashers from Parameters as per your option 2.

Would this provide a default high memory Parameters object? e.g. something like

from argon2 import PasswordHasher, HighMemoryParameters

high_mem_hasher = PasswordHasher.from_parameters(HighMemoryParameters)

@hynek
Copy link
Owner

hynek commented Oct 31, 2021

Yeah, I’d supply both RFC options at least. Maybe additionally the current defaults for people who want to keep them. Could live in a separate module argon2.profiles.RFC9106HighMemory or something.

hynek added a commit that referenced this issue Dec 5, 2021
Now that Argon2 is a proper RFC, we need to support it.

To stay more agile, this introduces the concept of profiles, based on the
existing `Parameters` class.

Fixes #101

Co-authored-by: Brendan McDonnell <[email protected]>
hynek added a commit that referenced this issue Dec 5, 2021
Now that Argon2 is a proper RFC, we need to support it.

To stay more agile, this introduces the concept of profiles, based on the
existing `Parameters` class.

Fixes #101

Co-authored-by: Brendan McDonnell <[email protected]>
hynek added a commit that referenced this issue Dec 5, 2021
Now that Argon2 is a proper RFC, we need to support it.

To stay more agile, this introduces the concept of profiles, based on the
existing `Parameters` class.

Fixes #101

Co-authored-by: Brendan McDonnell <[email protected]>
hynek added a commit that referenced this issue Dec 5, 2021
Now that Argon2 is a proper RFC, we need to support it.

To stay more agile, this introduces the concept of profiles, based on the
existing `Parameters` class.

Fixes #101

Co-authored-by: Brendan McDonnell <[email protected]>
@hynek hynek closed this as completed in #110 Dec 8, 2021
hynek added a commit that referenced this issue Dec 8, 2021
Now that Argon2 is a proper RFC, we need to support it.

To stay more agile, this introduces the concept of profiles, based on the
existing `Parameters` class.

Fixes #101

Co-authored-by: Brendan McDonnell <[email protected]>

Co-authored-by: Brendan McDonnell <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
2 participants