lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  PHC 
Open Source and information security mailing list archives
Hash Suite for Android: free password hash cracker in your pocket
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date: Mon, 14 Sep 2015 17:05:11 +0100
From: Hugo Landau <>
Subject: Re: [PHC] Specification of a modular crypt format

> -- A similar format should exist, that contains everything except the
> hash output. This is for compatibility with the Unix crypt() API. Let's
> call "salt string" the string without the hash output, and "hash string"
> the string with the hash output.

This is good, but I'd repeat this for configuration. It should be
possible to create a string free of both salt and hash. This could be
used for passing around configuration parameters in some circumstances.

Basically the idea, which seems to be quite universally adopted, is that
the fields are in the order of ident-config-salt-hash, i.e. from most
general to most specific.

> $<id>$[<param>=<value>(,<param>=<value>)*$]<salt>[$<hash>]

I gather this is coming from sha256/512-crypt's $rounds=...$ syntax, but
I'm not convinced it's warranted. The need for key-value extensibility
for password hashing functions is, presumably, nil, especially given
that no fields are now optional. This brings in unnecessary complexity
(and thus the increased chances that people will mess up
implementations). $<id>$<arg>$<arg2>$...$<argN>$<salt>$<hash> is simpler
to deal with, though I suppose
$<id>$<arg>,<arg2>,...,<argN>$<salt>$<hash> would also suffice if it's
desirable to limit the parameters to one field for some reason.

I also think parameter values can be limited to non-negative integers at
this time, unless you are aware of any password hashing schemes which
would be incompatible with this. This has the advantage that the grammar
of integers can be integrated into the definition, thus making the
determinism of the encoding formal.

Here's my proposed grammar in ABNF:

  hash-string   = salt-string '$' hash
  salt-string   = config-string '$' salt
  config-string = '$' scheme-identifier '$' scheme-specific-options

  scheme-identifier = 1*(ALPHA / DIGIT / '-')
  hash = base64-string
  salt = base64-string

  ; N is determined by scheme
  scheme-specific-options = N*N(scheme-option '$')
  scheme-option           = integer

  integer = '0' / (NZDIGIT *DIGIT)
  base64-string = *(ALPHA / DIGIT / '.' / '/')
  NZDIGIT = %x31-39

>I am not using standard Base64 (RFC 4648) for encoding of binary
strings, but the "traditional" variant which is already used in some
existing hash strings, for the following reasons:

I'm not convinced by this rationale. Firstly, I'm not aware of any
base64 functionality provided by programming language standard libraries
which does line wrapping, etc. The world seems to agree that 'base64'
has come to mean a certain thing, distinct from 'PEM base64' etc.

While it's true that RFC 4648 base64 generates padding, this can easily
be stripped. So this doesn't seem like a justification for using a
different 'alphabet' (and IIRC endianness of encoding). In other words,
this would be a gratuitous difference almost for the sake of
incompatibility. It seems like an overreaction to use something very
different because the more common choice is slightly off (but easily

While it's true that existing crypt() implementations and their base64
implementation is widespread, RFC 4648 base64 is more prevalent still.
And consider that the most pressing case for modern password hashing is
probably not in /etc/shadow, but in the user databases of large, popular
websites. Developers in this circumstance (or, preferably, people
developing password hashing libraries) will have RFC 4648 base64
libraries available to them, but if they have to use crypt() base64 they
may have to implement it themselves, which creates the risk that they
will implement it in a subtly buggy or broken fashion.

I say this from experience; I implemented sha512-crypt in Go, and had to
implement crypt() base64. Whereas if it had used RFC 4648 base64
existing base64 libraries could have been reused. Not really a problem,
but it feels like an unnecessary liability.

Powered by blists - more mailing lists