Page MenuHomeFreeBSD

Bug 182518 - [login.conf] Better Password Hashes
Needs ReviewPublic

Authored by on Jun 9 2018, 4:02 AM.


Group Reviewers

This patch contains:

  • updated libcrypt, which includes new api: crypt_makesalt
  • revised/rewritten crypt(3) manpage, detailing the uses of Modular Crypt Formats, and new crypt_makesalt api
  • refactored pam_unix to use crypt_makesalt, instead of its own format
  • refactored pw to support Modular Crypt Formats in login.conf

These things combined allow using Modular Crypt Formats in login.conf to be recognized by the system. Ultimately, this will allow selecting any supported crypt algorithm with whatever parameters that it supports, e.g. $2b$11$.

Contains modifications from the patch included in, rebased on -CURRENT.

Test Plan

Not sure what's appropriate.


Update passwd_format to $2b$11$:

  • add a user
  • verify hash in master.passwd begins with $2b$11$
  • verify login with pam_unix works

Change passwd_format to $6$rounds=10000$:

  • change user's password
  • verify hash in master.passwd begins with $6$rounds=10000$
  • verify login with pam_unix works

Diff Detail

Lint Skipped
Unit Tests Skipped

Event Timeline


This line renders wrong for David's name.

Fix accent on David's name, per imp feedback. marked an inline comment as done.

Fix loop always executing twice (in pw+pam_unix), with leaky memory.

There are a bunch of style issues with crypt.3. Can you run "mandoc -Tlint" and textproc/igor (from ports/packages) on it? It should give you some feedback where the problems are. For example, man pages need a line break after a sentence stop.

Thanks for the work!


(we use american english in the project)

Could you please split the proposed change to smaller pieces, so it would be easier to review?

(I've commented some issues with the proposed change inline, by the way).


Please use C99 or newer standard for definition instead of K&R main().


This is self-inflicted wound. Use crypt_r instead and drop all the locking (crypt is a non-thread safe wrapper of crypt_r).


See above.




Why is this API exposed to user? ("Do not add new functionality unless an implementor cannot complete a real application without it.")

There are multiple style and coding issues, by the way, please fix.


You are using only 3 bytes, why 4 here?


Please refactor the code, use strl* instead of strn*.


Could you please change the code to use a separate base64 buffer and use strlcat instead of operating on the output buffer directly?


Just use strlcat, the trailing nul is not actually written, by the way.



This revision now requires changes to proceed.Jul 28 2018, 12:09 AM

This update covers the linting, and simplified example code in the libcrypt manpage.

delphij requested changes to this revision.Aug 1 2018, 2:51 AM
delphij added inline comments.

This introduced a security vulnerability.

This revision now requires changes to proceed.Aug 1 2018, 2:51 AM marked 2 inline comments as done and an inline comment as not done.Aug 2 2018, 10:33 AM added inline comments.

Thank you for taking the time to review. This has been updated. In fairness, this example pre-dates the crypt_r in FreeBSD by 4+ years.


I will take care of the style (and strn*) items, please excuse.

With respect to the API, I think there's a good discussion to be had here.

It would seem that having the salt generation (and knowledge of what an appropriate salt is for the entire suite of algorithms supported by crypt) pushed into the consumer would be needlessly complex. It ossifies algorithm support all over the place.

This is not the only approach however, and perhaps we can take a page with the work done by the OpenBSD project in this space since the original patch was submitted:
^ gives cert error, by intent

i.e. crypt_newhash and crypt_checkpass specifically.

Also, there's some old old discussion available on the mailing lists as well, if that interests you. I've linked into the thread here:

In fairness, this example pre-dates the crypt_r in FreeBSD by 4+ years.

Indeed - apologies that this issue has remained open for so long.

One note, for the next update you submit to Phabricator can you please include full context - i.e., with git diff -U99999 or svn diff --diff-cmd=diff -x -U999999 (see for more info).


Thanks for the context. Is there some reason not to have the crypt functions to generate a salt on demand instead (e.g. when the passed salt is too short, which is something that we already will check, and the individual crypt function actually knows better)?

It worried me because with your new API, the callers are now required to do more work (allocating memory, check for the result, etc.).


I'm not sure, it sounds like a good idea. I feel like having crypt do that automatically would be pretty surprising though, there's no precedent? (There's also no precedent for crypt_makesalt, but there are a few crypt_gensalt implementations.)

With regard to the more work, perhaps that's also a benefit:

  • For the memory allocation, the example code and the updated user-land could be easily simplified by allocating a static buffer of _PASSWORD_LEN, which would be no worse than the current crypt_data constraint. The salt will never be longer than the crypt_data buffer, by definition. The retry logic could be removed, and just fail in this case. This isn't great, but it should only hit this code path if the the ABI changes under the consumer, and should be a simple if. If clients wish to protect against ABI changes (what does that even mean?) with retry logic, they could - but perhaps it's wrong-headed to have that as I've provided it.
  • For the format case, I think having feedback that a format isn't supported by the crypt implementation is valuable. I imagine most people (i.e. sysadmins) specifying the crypt format in a configuration file, and the consumer utility being agnostic. How would we otherwise signal an unsupported or invalid crypt request? I don't think returning a "default" hash is a good idea (if we simply extend crypt), and a DES crypt would be particularly damaging - but would be required for backward compatibility.

I think the format validation is a strong case for this. The crypt_newhash approach also allows to signal an invalid format, but doesn't differentiate a short buffer with an invalid format. What do you think?

I'm hopeful that this fixes style, and other suggestions from delphij.


Any thoughts on a sensible way to move this portion forward?

I would submit a crypt_newhash approach similar to that of OpenBSD, if that was agreed to be a sensible way to proceed.

Any chance of this being moved forward in time for the 12 branch?

All comments are minor.


why was previous char * enclosed in quotes, but not this one?


I'd combine these two statements, into:
Password hashing is different than a standard one way hash function in that it tries to make it difficult to recover a low-entropy


What should be used instead?


concerted that it's not listed as $digit$ or $digit[variant]$, because this means that we cannot have more than 10 variants.. as $11$ will match md5-crypt per this spec. We are already up to 6...


this should probably be removed, as the next paragraph's It is unclear.


again, next paragraph It isn't clear.


space between 3DES and comma.


was the addition of the semicolon intentional? this is usually left off and it looks like it may cause a compile error.


might want to make this a define, like SALTBUFFER or something to replace the SALTSIZE define. There was another location this size was used.

Minor comment - results of real-world testing of cracking resistance, both for the 11.x defaults and for those proposed by D15713.

Test platform: Ubuntu 16.04, 6x GTX 1080 GPUs, NVIDIA driver 418.43, hashcat 6.x pre-release (GitHub master, v5.1.0-820-g319bf801)

Summary (H/s = hashes per second, one complete cracking attempt):

sha512crypt, 11.x default:           Speed.#*.........:   912.9 kH/s
sha512crypt, rounds=10000 (D15713):  Speed.#*.........:   457.5 kH/s
bcrypt, cost 4 (11.x default):       Speed.#*.........:   248.1 kH/s
bcrypt, cost 11 (D15713):            Speed.#*.........:     2026 H/s
bcrypt, cost 12:                     Speed.#*.........:     1012 H/s

Full testing output here:

As an attacker, bcrypt cost 12 is the most frustrating. :)

For future work, debdrup suggested tying work factor to local testing, similar to the 1-second GELI autotuning.

Any chance that this patch would make it into 13.0 RELEASE?