Generating crypt() Salt Strings

Generating salt strings for crypt() used to be easy. All it took was to randomly choose two characters, each from the set [A-Za-z0-9./]. And even "random" number generation was easy. Just use rand().

Now it is harder. Not only do different systems use different salt string formats, but the best pseudo-random number generators seem to be system-specific, or at least not part of the base operating system libraries. And new salt formats and better generators appear all the time.

This situation is a problem for portable programming. The traditional methods are portable, yet weak. Newer methods are stronger, but less portable.

Generic Salt Generator

gensalt() is a function to generate crypt() salt string based on a template supplied at run-time. The function can optionally use a programmer-supplied pseudo-random number generator to allow better generators to be plugged in when necessary. The function looks like this:

        char *
        gensalt(char *template, int (f)(int));

template describes what the salt looks like and how it is generated. A template is a mix of literal characters and generator descriptions. Literal characters are copied to the salt directly. Generator descriptions cause one or more random characters to be generated. Special characters can be escaped by preceding them with a backslash. Arbitrary characters can be specified with the usual \ooo octal conventions.

Generator descriptions look like regular expression ranges. For example, a generator description for the traditional salts looks like this:

        [A-Za-z0-9./]{2}
This causes the generator to produce two random characters from the set between the square brackets. Ranges work like regular expression ranges do.

A template for a short MD5 salt looks like this:

        $1$[A-Za-z0-9./]{8}

If template is NULL, the traditional template is used by default.

f is an optional function which can be used to provide better random numbers. This function takes a single int argument n. It should return a random int in the range 0..n-1. If f is NULL, the default function:

        rand() % n
is used, which isn't all that good.

If gensalt() cannot generate a salt, it will record an error message and return NULL. To retrieve the error message, use gensalt_msg():

        char *
        gensalt_msg(void);

gensalt() returns a dynamically allocated string which should not be altered. Its location and contents may change between calls.

Common Salt Formats

Method Format Supporting Systems
Traditional [A-Za-z0-9./]{2} Probably all systems support the traditional crypt() salt strings.
Extended DES _[A-Za-z0-9./]{8} FreeBSD, NetBSD, OpenBSD
Short MD5 $1$[A-Za-z0-9./]{8} FreeBSD, NetBSD, OpenBSD, glibc2
Long MD5 $1$[A-Za-z0-9./]{16} ?
Short Blowfish $2$[A-Za-z0-9./]{22} FreeBSD?
Long Blowfish $2a$rounds$[A-Za-z0-9./]{22}
roundsis a number from 04 through 12
OpenBSD
Blowfish $12$ OpenBSD? reference

Sources

gensalt.c - gensalt() and gensalt_msg()
gensalt.h
gensalt-test.c - test program
Makefile