diff --git a/lib/libcrypt/crypt.3 b/lib/libcrypt/crypt.3 index f14a6eb9d902..50829c2fa43b 100644 --- a/lib/libcrypt/crypt.3 +++ b/lib/libcrypt/crypt.3 @@ -29,7 +29,7 @@ .\" .\" $FreeBSD$ .\" -.Dd April 9, 2011 +.Dd March 9, 2014 .Dt CRYPT 3 .Os .Sh NAME @@ -63,11 +63,16 @@ Currently these include the .Tn MD5 hash, .Tn NT-Hash -(compatible with Microsoft's NT scheme) +.Pq compatible with Microsoft's NT scheme and .Tn Blowfish . -The algorithm used will depend upon the format of the Salt (following -the Modular Crypt Format (MCF)), if +The algorithm used will depend upon the format of the Salt +.Po +following +the Modular Crypt Format +.Pq MCF +.Pc , +if .Tn DES and/or .Tn Blowfish @@ -77,8 +82,10 @@ has been called to change the default. .Pp The first argument to .Nm -is the data to hash (usually a password), in a -.Dv null Ns -terminated +is the data to hash +.Pq usually a password , +in a +.Dv NUL Ns -terminated string. The second is the salt, in one of three forms: .Pp @@ -96,22 +103,19 @@ If it begins with the string then the Modular Crypt Format is used, as outlined below. .It Traditional If neither of the above is true, it assumes the Traditional Format, -using the entire string as the salt (or the first portion). +using the entire string as the salt +.Pq or the first portion . .El .Pp All routines are designed to be time-consuming. -A brief test on a -.Tn Pentium -166/MMX shows the -.Tn DES -crypt to do approximately 2640 crypts -a CPU second and MD5 to do about 62 crypts a CPU second. .Ss DES Extended Format: The .Ar key -is divided into groups of 8 characters (the last group is null-padded) -and the low-order 7 bits of each character (56 bits per group) are -used to form the +is divided into groups of 8 characters +.Pq the last group is NUL-padded +and the low-order 7 bits of each character +.Pq 56 bits per group +are used to form the .Tn DES key as follows: the first group of 56 bits becomes the initial @@ -127,7 +131,8 @@ The salt is a 9-character array consisting of an underscore followed by 4 bytes of iteration count and 4 bytes of salt. These are encoded as printable characters, 6 bits per character, least significant character first. -The values 0 to 63 are encoded as ``./0-9A-Za-z''. +The values 0 to 63 are encoded as +.Dq ./0-9A-Za-z . This allows 24 bits for both .Fa count and @@ -138,7 +143,8 @@ The introduces disorder in the .Tn DES algorithm in one of 16777216 or 4096 possible ways -(i.e., with 24 or 12 bits: if bit +.Po +i.e., with 24 or 12 bits: if bit .Em i of the .Ar salt @@ -148,7 +154,8 @@ and .Em i+24 are swapped in the .Tn DES -E-box output). +E-box output +.Pc . .Pp The .Tn DES @@ -157,11 +164,13 @@ key is used to encrypt a 64-bit constant using iterations of .Tn DES . The value returned is a -.Dv null Ns -terminated -string, 20 or 13 bytes (plus null) in length, consisting of the +.Dv NUL Ns -terminated +string, 20 or 13 bytes +.Pq plus NUL +in length, consisting of the .Ar salt followed by the encoded 64-bit encryption. -.Ss "Modular" crypt: +.Ss Modular crypt: If the salt begins with the string .Fa $digit$ then the Modular Crypt Format is used. @@ -170,11 +179,10 @@ The represents which algorithm is used in encryption. Following the token is the actual salt to use in the encryption. -The length of the salt is limited -to 8 characters--because the length of the returned output is also limited -(_PASSWORD_LEN). -The salt must be terminated with the end of the string -(NULL) or a dollar sign. +The maximum length of the salt used depends upon the module. +The salt must be terminated with the end of the string character +.Pq NUL +or a dollar sign. Any characters after the dollar sign are ignored. .Pp Currently supported algorithms are: @@ -199,7 +207,7 @@ An example salt would be: .Bl -tag -width 6n -offset indent .It Cm "$4$thesalt$rest" .El -.Ss "Traditional" crypt: +.Ss Traditional crypt: The algorithm used will depend upon whether .Fn crypt_set_format has been called and whether a global default format has been specified. @@ -216,7 +224,7 @@ if it is available, or MD5 if not. .Pp How the salt is used will depend upon the algorithm for the hash. For -best results, specify at least two characters of salt. +best results, specify at least eight characters of salt. .Pp The .Fn crypt_get_format diff --git a/lib/libcrypt/crypt.c b/lib/libcrypt/crypt.c index bfcbb2049b5a..040fdc1b90af 100644 --- a/lib/libcrypt/crypt.c +++ b/lib/libcrypt/crypt.c @@ -1,6 +1,7 @@ -/* - * Copyright (c) 1999 - * Mark Murray. All rights reserved. +/*- + * Copyright (c) 1999 Mark Murray + * Copyright (c) 2014 Dag-Erling Smørgrav + * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -28,114 +29,88 @@ __FBSDID("$FreeBSD$"); #include -#include + #include +#include #include + #include "crypt.h" -static const struct { +/* + * List of supported crypt(3) formats. The first element in the list will + * be the default. + */ +static const struct crypt_format { const char *const name; char *(*const func)(const char *, const char *); const char *const magic; -} crypt_types[] = { -#ifdef HAS_DES - { - "des", - crypt_des, - NULL - }, -#endif - { - "md5", - crypt_md5, - "$1$" - }, +} crypt_formats[] = { + /* default format */ + { "sha512", crypt_sha512, "$6$" }, + + /* other supported formats */ + { "md5", crypt_md5, "$1$" }, #ifdef HAS_BLOWFISH - { - "blf", - crypt_blowfish, - "$2" - }, + { "blf", crypt_blowfish, "$2" }, #endif - { - "nth", - crypt_nthash, - "$3$" - }, - { - "sha256", - crypt_sha256, - "$5$" - }, - { - "sha512", - crypt_sha512, - "$6$" - }, - { - NULL, - NULL, - NULL - } + { "nth", crypt_nthash, "$3$" }, + { "sha256", crypt_sha256, "$5$" }, +#ifdef HAS_DES + { "des", crypt_des, "_" }, +#endif + + /* sentinel */ + { NULL, NULL, NULL } }; -#ifdef HAS_DES -#define CRYPT_DEFAULT "des" -#else -#define CRYPT_DEFAULT "md5" -#endif +static const struct crypt_format *crypt_format = &crypt_formats[0]; -static int crypt_type = -1; - -static void -crypt_setdefault(void) -{ - size_t i; - - if (crypt_type != -1) - return; - for (i = 0; i < sizeof(crypt_types) / sizeof(crypt_types[0]) - 1; i++) { - if (strcmp(CRYPT_DEFAULT, crypt_types[i].name) == 0) { - crypt_type = (int)i; - return; - } - } - crypt_type = 0; -} +#define DES_SALT_ALPHABET \ + "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" +/* + * Returns the name of the currently selected format. + */ const char * crypt_get_format(void) { - crypt_setdefault(); - return (crypt_types[crypt_type].name); + return (crypt_format->name); } +/* + * Selects the format to use for subsequent crypt(3) invocations. + */ int -crypt_set_format(const char *type) +crypt_set_format(const char *format) { - size_t i; + const struct crypt_format *cf; - crypt_setdefault(); - for (i = 0; i < sizeof(crypt_types) / sizeof(crypt_types[0]) - 1; i++) { - if (strcmp(type, crypt_types[i].name) == 0) { - crypt_type = (int)i; + for (cf = crypt_formats; cf->name != NULL; ++cf) { + if (strcasecmp(cf->name, format) == 0) { + crypt_format = cf; return (1); } } return (0); } +/* + * Hash the given password with the given salt. If the salt begins with a + * magic string (e.g. "$6$" for sha512), the corresponding format is used; + * otherwise, the currently selected format is used. + */ char * crypt(const char *passwd, const char *salt) { - size_t i; + const struct crypt_format *cf; - crypt_setdefault(); - for (i = 0; i < sizeof(crypt_types) / sizeof(crypt_types[0]) - 1; i++) { - if (crypt_types[i].magic != NULL && strncmp(salt, - crypt_types[i].magic, strlen(crypt_types[i].magic)) == 0) - return (crypt_types[i].func(passwd, salt)); - } - return (crypt_types[crypt_type].func(passwd, salt)); + for (cf = crypt_formats; cf->name != NULL; ++cf) + if (cf->magic != NULL && strstr(salt, cf->magic) == salt) + return (cf->func(passwd, salt)); +#ifdef HAS_DES + if (strlen(salt) == 13 && strspn(salt, DES_SALT_ALPHABET) == 13) + return (crypt_des(passwd, salt)); +#endif + return (crypt_format->func(passwd, salt)); }