Class ModularPbkdf2PasswordEncoder

java.lang.Object
com.codename1.backend.security.crypto.ModularPbkdf2PasswordEncoder
All Implemented Interfaces:
PasswordEncoder

public final class ModularPbkdf2PasswordEncoder extends Object implements PasswordEncoder

PBKDF2 password hashes in the self-describing formats other frameworks store, read as they write them: the digest and the round count come from the stored value, so every row verifies whatever its era's settings were.

format stored value
ModularPbkdf2PasswordEncoder.Format.DJANGO pbkdf2_sha256$<rounds>$<salt>$<base64 hash> (also pbkdf2_sha1)
ModularPbkdf2PasswordEncoder.Format.PASSLIB $pbkdf2-sha256$<rounds>$<ab64 salt>$<ab64 hash> (also $pbkdf2$, $pbkdf2-sha512$)
ModularPbkdf2PasswordEncoder.Format.WERKZEUG pbkdf2:sha256:<rounds>$<salt>$<hex hash> (also sha1, sha512)

Register it under an id of its own and give the imported hashes that prefix:

Map<String, PasswordEncoder> encoders = new LinkedHashMap<>();
encoders.put("pbkdf2-sha256", new Pbkdf2Sha256PasswordEncoder());
encoders.put("django", new ModularPbkdf2PasswordEncoder(ModularPbkdf2PasswordEncoder.Format.DJANGO));
PasswordEncoder passwords = new DelegatingPasswordEncoder("pbkdf2-sha256", encoders);
// a row imported as "{django}pbkdf2_sha256$600000$..." verifies, and is
// re-hashed with the default when its owner signs in

upgradeEncoding(String) is true for every value: these are formats to migrate away from, not to keep writing.

A stored value names its own work factor, so it is bounded. One above maxRounds (5,000,000 by default) does not verify -- a hash that asked for a billion rounds would hold the host thread it runs on for minutes. Werkzeug values without a round count are refused too: the count they used was the default of whichever Werkzeug release wrote them, and guessing it would either fail every such login or need one PBKDF2 run per guess.

  • Constructor Details

  • Method Details

    • setMaxRounds

      public void setMaxRounds(int maxRounds)
      The most rounds a stored value may ask for. Default 5,000,000.
    • setEncodeRounds

      public void setEncodeRounds(int rounds)
      Rounds encode(CharSequence) writes. Default 600,000 with SHA-256.
    • encode

      public String encode(CharSequence rawPassword)
      A new SHA-256 hash in this format. Meant for fixtures and for tests of a migration; a running server writes its default encoder's format.
      Specified by:
      encode in interface PasswordEncoder
    • matches

      public boolean matches(CharSequence rawPassword, String encodedPassword)
      Description copied from interface: PasswordEncoder
      Whether rawPassword is the password encodedPassword was made from.
      Specified by:
      matches in interface PasswordEncoder
    • upgradeEncoding

      public boolean upgradeEncoding(String encodedPassword)
      Description copied from interface: PasswordEncoder
      Whether encodedPassword should be encoded again for better protection: it was made by an older scheme, or with fewer rounds than this encoder uses now.
      Specified by:
      upgradeEncoding in interface PasswordEncoder
    • isReadable

      public boolean isReadable(String encodedPassword)
      Whether encodedPassword is a value of this format this encoder would try to verify: the layout, a known digest and a round count within maxRounds. What a migration asks before importing a row.