Follow @Openwall on Twitter for new release announcements and other news
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date: Fri, 6 Mar 2015 13:17:06 +0300
From: Solar Designer <solar@...nwall.com>
To: john-dev@...ts.openwall.com
Subject: Re: Generic crypt(3)

On Fri, Mar 06, 2015 at 05:28:08PM +0800, Kai Zhao wrote:
> The right-format one took a lot of time and I canceled. The changed one
> took a lot of time too. I think
> the changed one is wrong-format. Since there is a character "???" . crypt(3)
> man page shows that the
> format should be : "$id$salt$encrypted". Also the characters in "salt" and
> "encrypted" are draw from
> the set [a-zA-Z0-9./];
> 
> However, john did not recognize the changed one as wrong-format and tried
> to crack it.
[...]
> Is this a bug?

No, not a bug, because the generic crypt(3) format is special.  Its
primary purpose is to support whatever hash types the underlying system
might support, even if those are not known to JtR.  While we could
special-case sha512crypt - and in fact, we do have some special-case
logic to handle it more optimally already - we're not expected to do
that, and in fact we can't do it for hash types that we're not yet aware
of (that might appear and be introduced into a system's crypt(3) in the
future).  So we can't fully patch the behavior you observed to ensure
that an invalid hash encoding would never be loaded by the generic
crypt(3) format.

For other JtR formats, this sort of behavior would most likely indicate
a bug that we could patch.  So please keep searching!  For example, will
your wrong-format hash be loaded by jumbo's sha512crypt,
sha512crypt-opencl, or sha512crypt-cuda formats?  If so, that's a bug
that we should patch.  Please test and let us know.

Regarding the special-casing I mentioned, right now c3_fmt.c does it to
determine the salt length for the hash types it's specifically aware of.
This allows JtR to detect matching salts for those.  If a yet unknown
hash type is processed by c3_fmt.c, detection of matching salts would
not work for that hash type - but other than that, passwords would be
tested against those hashes correctly anyway.

We could extend the special-casing so that we also validate the encoding
of the entire hashes.  So far, we haven't bothered to do that, and I'm
not sure if we should.  Like I said above, I think this is not expected
of the generic crypt(3) format.  But it would not hurt to have this
extra either, except in terms of code complexity.  So I think this is a
topic we may revisit if/once we get some generic hash encoding
validation function into JtR (regexp match alike), which is something
Alexander Cherepanov was/is proposing.  We might introduce this sort of
function to simplify and make more reliable the valid() methods in other
formats, and if/once we do I would not mind us using it in the generic
crypt(3) format as well (obviously, only for the crypt(3) hash types
we're aware of at a given moment).

BTW, it's crucial not to be too strict.  We need to accept invalid salts
that could be in use somewhere in practice.  For example, you wrote:

> format should be : "$id$salt$encrypted". Also the characters in "salt" and
> "encrypted" are draw from
> the set [a-zA-Z0-9./];

While ideally JtR should not load for cracking hash encodings where the
hash encoding itself is impossible (the wrongly-named "encrypted"
portion above), because it'd never get a match for those, it should
nevertheless load those where the salt portion uses invalid characters,
if there exists a defensive-use implementation that would accept such
invalid salts (and process them in some specific way, which JtR should
mimic).

For example, JtR takes specific care to process invalid salts for
descrypt in the same way as certain defensive implementations do
(although there are also other defensive implementations that process
invalid descrypt salts differently; there's room for improvement here).

Another curious detail is that while the specification you quoted above
allows for any of the 64 characters from [a-zA-Z0-9./] to be used in any
character position in the actual hash encoding (the "encrypted"
portion), in practice the very last character usually encodes fewer bits
from the binary hash value, so fewer different characters are possible
in the last character of the encoding.  Again, JtR's descrypt formats'
valid() is aware of this, imposing this extra restriction (and thus not
loading for cracking some valid-looking but actually impossible
13-character strings).  The same should apply for sha512crypt and
sha256crypt, since neither 512 nor 256 is a multiple of 6, but I don't
think our existing sha{256,512}crypt* formats' valid() functions are
currently aware of this detail.  We could enhance them in this respect.

Thanks,

Alexander

Powered by blists - more mailing lists

Confused about mailing lists and their use? Read about mailing lists on Wikipedia and check out these guidelines on proper formatting of your messages.