CRYPT_GENSALT(3)

πŸ’– CRYPT_GENSALT(3) β€” the libcrypt glow-up guide πŸ’–

okay bestie, sit DOWN. this is a Library Functions Manual page, and today's main characters are crypt_gensalt, crypt_gensalt_rn, and crypt_gensalt_ra β€” three lil functions that encode settings for passphrase hashing. they don't do the hashing themselves, they just prep the ✨setting✨ so the hashing can happen. supportive icons fr. 🫢


🌸 NAME 🌸

crypt_gensalt, crypt_gensalt_rn, crypt_gensalt_ra β€” encode settings for passphrase hashing πŸ’…


πŸ“š LIBRARY πŸ“š

Crypt Library β€” that's libcrypt, and you link it with -lcrypt. literally just that.


✨ SYNOPSIS ✨

#include <crypt.h>

char *
crypt_gensalt(const char *prefix, unsigned long count,
    const char *rbytes, int nrbytes);

char *
crypt_gensalt_rn(const char * prefix, unsigned long count,
    const char *rbytes, int nrbytes, char * output, int output_size);

char *
crypt_gensalt_ra(const char *prefix, unsigned long count,
    const char *rbytes, int nrbytes);

(yes, crypt_gensalt_rn has a lil space in const char * prefix and the others don't. i don't make the rules. i just respect them. πŸ™ˆ)


πŸŽ€ DESCRIPTION πŸŽ€

so what do these three do? they compile a string for use as the setting argument to crypt, crypt_r, crypt_rn, and crypt_ra. basically they build the little config blob that tells the hasher how you want your password scrambled. πŸ”₯

here's the tea on the arguments:

  • prefix β€” picks which hashing method you're gonna use. main character energy, chooses the vibe.
  • count β€” controls the processing cost of the hash. the valid range and the exact meaning of count both depend on the hashing method, but the vibe is: bigger number = more costly hash, in CPU time and possibly memory usage too. it's giving "expensive on purpose." πŸ’Έ
  • rbytes β€” should point to nrbytes cryptographically random bytes, and those get used as the β€œsalt.” πŸ§‚

now the special cases, and bestie, these matter:

  • if prefix is a null pointer, the best available hashing method gets selected automatically. iconic, love that for you. πŸ’–
  • CAUTION β€” if prefix is an empty string, the β€œtraditional” DES-based hashing method gets selected instead. and that method is unacceptably weak by modern standards. like, do not. 🚩
  • if count is 0, a low default cost gets selected.
  • if rbytes is a null pointer, an appropriate number of random bytes gets pulled from the operating system, and nrbytes is ignored. ✨auto-entropy✨

and go read crypt(5) for the other strings you can use as prefix, plus the valid values of count for each one. it's the encyclopedia, i'm just the group chat.


πŸ¦‹ RETURN VALUES πŸ¦‹

all three return a pointer to an encoded setting string. and that string is chef's kiss:

  • entirely printable ASCII
  • contains no whitespace
  • does not contain any of these characters: ':', ';', '*', '!', '\'

want more detail on the format? crypt(5) again. that page is carrying this whole family. πŸ’ͺ

on error, they return a null pointer and set errno to an appropriate error code.

⚠️ when the functions succeed, the value of errno is unspecified and must not be relied upon. she doesn't owe you consistency. πŸ’€

now, each function stores its result somewhere different, and this is where the drama lives:

πŸ’œ crypt_gensalt

crypt_gensalt places its result in a static storage area, which will be overwritten by subsequent calls to crypt_gensalt.

in this version of libcrypt, that static storage area is allocated separately for each thread β€” but portable code should not call crypt_gensalt from multiple threads simultaneously. (per-thread storage is a treat, not a promise. πŸŽ€)

it's also not recommended to use the pointer returned as an argument for another call to crypt_gensalt, because some implementations β€” including earlier releases of libxcrypt β€” may overwrite the underlying static output buffer before computing the setting. 😭

however, it is safe to pass the string returned by crypt_gensalt directly to crypt without copying it β€” each function has its own static storage area. besties sharing a shelf, not a plate. πŸ“

πŸ’œ crypt_gensalt_rn

crypt_gensalt_rn places its result in the supplied output buffer, which has output_size bytes of storage available. output_size should be greater than or equal to CRYPT_GENSALT_OUTPUT_SIZE.

it's also not recommended to use the pointer returned as an argument for another call to crypt_gensalt_rn while using the same output buffer for subsequent calls β€” because again, some implementations, including earlier releases of libxcrypt, may overwrite the supplied buffer before computing the setting. πŸ’€

πŸ’œ crypt_gensalt_ra

crypt_gensalt_ra allocates memory for its result using malloc(3). so obviously you should free it with free(3) after use. clean up after yourself, queen. πŸ‘‘

🚨 one more error behavior

upon error, in addition to returning a null pointer, crypt_gensalt and crypt_gensalt_rn will write an invalid setting string to their output buffer, if there is enough space. that string will begin with a '*' and will not be equal to prefix. so like… if you see a star, that's the sad path. ⭐


πŸ”₯ ERRORS πŸ”₯

  • EINVAL β€” prefix is invalid or not supported by this implementation; count is invalid for the requested prefix; or the input nrbytes is insufficient for the smallest valid salt with the requested prefix.
  • ERANGE β€” crypt_gensalt_rn only: output_size is too small to hold the compiled setting string. not enough room bestie 😭
  • ENOMEM β€” failed to allocate internal scratch memory. and for crypt_gensalt_ra only: also failed to allocate memory for the compiled setting string.
  • ENOSYS, EACCES, EIO, etc. β€” obtaining random bytes from the operating system failed. this can only happen when rbytes is a null pointer.

🌈 FEATURE TEST MACROS 🌈

these macros are defined by <crypt.h>:

  • CRYPT_GENSALT_IMPLEMENTS_DEFAULT_PREFIX β€” a null pointer can be specified as the prefix argument. πŸ’…
  • CRYPT_GENSALT_IMPLEMENTS_AUTO_ENTROPY β€” a null pointer can be specified as the rbytes argument. ✨

πŸ‘‘ PORTABILITY NOTES πŸ‘‘

okay this section is the "don't get caught out in the wild" section. pay attention. πŸ‘€

crypt_gensalt, crypt_gensalt_rn, and crypt_gensalt_ra are not part of any standard. they originate with the Openwall project. there is also a function named crypt_gensalt on Solaris 10 and newer β€” but its prototype and semantics differ. so like, same name, different girl. πŸ’€

some implementations of crypt_gensalt use a single storage area for all callers, even in the presence of threads. this library uses per-thread storage areas, but portable code should avoid calling crypt_gensalt from multiple threads simultaneously. instead it is strongly advised to allocate thread-specific buffers of CRYPT_GENSALT_OUTPUT_SIZE length from within each thread itself, and to use those buffers with the re-entrant interface provided through crypt_gensalt_rn, or crypt_gensalt_ra. do that. fr fr. 🫢

the default prefix and auto entropy features are available since libxcrypt version 4.0.0. portable software can use feature test macros to find out whether null pointers can be used for the prefix and rbytes arguments.

and the set of supported hashing methods varies considerably from system to system. no cap. 🌍


πŸ’… ATTRIBUTES πŸ’…

for an explanation of the terms used in this section, see attributes(7).

  • crypt_gensalt β€” Thread safety: MT-Safe* ⭐
  • crypt_gensalt_rn, crypt_gensalt_ra β€” Thread safety: MT-Safe πŸ’–
🚨 * β€” In this implementation. Do NOT rely on this to be portable behavior. See β€œPORTABILITY NOTES”.

(the original renders this as a table, but i'm a bullet-list girlie. the facts are identical, don't @ me. πŸŽ€)


🌸 SEE ALSO 🌸

crypt(3), getpass(3), getpwent(3), shadow(3), login(1), passwd(1), crypt(5), passwd(5), shadow(5), pam(8)


and that's the whole page, bestie!! πŸ¦‹βœ¨ this was brought to you by the Openwall Project, dated March 27, 2024 β€” go forth and generate your salt responsibly, and remember: null prefix = best method, empty prefix = DES = 🚩🚩🚩. periodt. πŸ’–

πŸ“¦ where this page comes from
  • fedora 43: libxcrypt-devel 4.5.2-1.fc43 Β· LGPL-2.1-or-later AND BSD-3-Clause AND BSD-2-Clause AND BSD-2-Clause-FreeBSD AND 0BSD AND CC0-1.0 AND LicenseRef-Fedora-Public-Domain
  • fedora 43: libxcrypt-devel 4.5.2-1.fc43 Β· LGPL-2.1-or-later AND BSD-3-Clause AND BSD-2-Clause AND BSD-2-Clause-FreeBSD AND 0BSD AND CC0-1.0 AND LicenseRef-Fedora-Public-Domain
  • fedora 44: libxcrypt-devel 4.5.2-3.fc44 Β· LGPL-2.1-or-later AND BSD-3-Clause AND BSD-2-Clause AND BSD-2-Clause-FreeBSD AND 0BSD AND CC0-1.0 AND LicenseRef-Fedora-Public-Domain
  • fedora 44: libxcrypt-devel 4.5.2-3.fc44 Β· LGPL-2.1-or-later AND BSD-3-Clause AND BSD-2-Clause AND BSD-2-Clause-FreeBSD AND 0BSD AND CC0-1.0 AND LicenseRef-Fedora-Public-Domain
  • πŸ’– girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms