FreeBSD Bugzilla – Attachment 173188 Details for
Bug 182518
[login.conf] Better Password Hashes
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
correct crypt_makesalt return code documentation
crypt-patch-20160801-2 (text/plain), 51.76 KB, created by
Derek
on 2016-08-02 11:14:25 UTC
(
hide
)
Description:
correct crypt_makesalt return code documentation
Filename:
MIME Type:
Creator:
Derek
Created:
2016-08-02 11:14:25 UTC
Size:
51.76 KB
patch
obsolete
>diff --git a/include/unistd.h b/include/unistd.h >index 0d20027..6d00db2 100644 >--- a/include/unistd.h >+++ b/include/unistd.h >@@ -290,6 +290,8 @@ typedef __useconds_t useconds_t; > #define _SC_NPROCESSORS_CONF 57 > #define _SC_NPROCESSORS_ONLN 58 > #define _SC_CPUSET_SIZE 122 >+#define CRYPT_FORMAT_MAX_LEN 20 /* currently strlen("$6$rounds=999999999$") == 20 */ >+#define CRYPT_SALT_MAX_LEN 37 /* currently strlen("$6$rounds=999999999$AAAABBBBCCCCDDDD$") == 37 */ > #endif > > /* Extensions found in Solaris and Linux. */ >@@ -490,6 +492,7 @@ int check_utility_compat(const char *); > const char * > crypt_get_format(void); > int crypt_set_format(const char *); >+int crypt_makesalt(char *, const char *, size_t *); > int des_cipher(const char *, char *, long, int); > int des_setkey(const char *key); > int dup3(int, int, int); >diff --git a/lib/libcrypt/Makefile b/lib/libcrypt/Makefile >index 3b982a3..1f69971 100644 >--- a/lib/libcrypt/Makefile >+++ b/lib/libcrypt/Makefile >@@ -17,7 +17,7 @@ SRCS= crypt.c misc.c \ > crypt-sha256.c sha256c.c \ > crypt-sha512.c sha512c.c > MAN= crypt.3 >-MLINKS= crypt.3 crypt_get_format.3 crypt.3 crypt_set_format.3 >+MLINKS= crypt.3 crypt_makesalt.3 crypt.3 crypt_get_format.3 crypt.3 crypt_set_format.3 > CFLAGS+= -I${.CURDIR}/../libmd -I${.CURDIR}/../libutil \ > -I${.CURDIR}/../../sys/crypto/sha2 > >diff --git a/lib/libcrypt/crypt.3 b/lib/libcrypt/crypt.3 >index 828c37f..0e07699 100644 >--- a/lib/libcrypt/crypt.3 >+++ b/lib/libcrypt/crypt.3 >@@ -1,6 +1,7 @@ > .\" FreeSec: libcrypt for NetBSD > .\" > .\" Copyright (c) 1994 David Burren >+.\" Copyright (c) 2015 Derek Marcotte > .\" All rights reserved. > .\" > .\" Redistribution and use in source and binary forms, with or without >@@ -15,10 +16,10 @@ > .\" may be used to endorse or promote products derived from this software > .\" without specific prior written permission. > .\" >-.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND >+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND > .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE > .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE >-.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE >+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE > .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL > .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS > .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) >@@ -29,282 +30,423 @@ > .\" > .\" $FreeBSD$ > .\" >-.Dd March 9, 2014 >-.Dt CRYPT 3 >+.Dd March 9, 2015 >+.Dt LIBCRYPT 3 > .Os > .Sh NAME >-.Nm crypt >-.Nd Trapdoor encryption >+.Nm crypt , >+.Nm crypt_makesalt , >+.Nm crypt_get_format , >+.Nm crypt_set_format >+.Nd "library for password hashing" > .Sh LIBRARY > .Lb libcrypt > .Sh SYNOPSIS > .In unistd.h >-.Ft char * >+.Ft "char *" > .Fn crypt "const char *key" "const char *salt" >-.Ft const char * >+.Ft "int" >+.Fn crypt_makesalt "char *output" "const char *format" "size_t *out_len" >+.Ft "const char *" > .Fn crypt_get_format "void" >-.Ft int >+.Ft "int" > .Fn crypt_set_format "const char *string" > .Sh DESCRIPTION >-The >-.Fn crypt >-function performs password hashing with additional code added to >-deter key search attempts. >-Different algorithms can be used to >-in the hash. >-.\" >-.\" NOTICE: >-.\" If you add more algorithms, make sure to update this list >-.\" and the default used for the Traditional format, below. >-.\" >-Currently these include the >-.Tn NBS >-.Tn Data Encryption Standard (DES) , >-.Tn MD5 >-hash, >-.Tn NT-Hash >-.Pq compatible with Microsoft's NT scheme >-and >-.Tn Blowfish . >-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 >-is installed or not, and whether >+The >+.Nm libcrypt >+library covers functions related to password hashing. >+.Pp >+Password hashing is different than a standard one way hash function. Password hashing tries to make it difficult to recover a low-entropy key >+.Pq e.g. a typed password >+from the resultant output hash. Offline recovery by exhaustive key search >+.Pq brute-force and dictionary attacks >+is stymied by the password hashing being one-way, and often computationally expensive. Different algorithms can be selected to produce the password hash, with varying ability to effectively deter key search attempts. >+.Pp >+The hashing algorithm to be used for an invocation of crypt is chosen by supplying a salt parameter of a particular format. The algorithms currently supported are: >+.Sx bcrypt , >+.Sx sha512-crypt , >+.Sx sha256-crypt , >+.Sx md5-crypt , >+.Sx DES Extended Format , >+.Sx Traditional DES Format , >+and >+.Sx NT-Hash . >+.Pp >+Current computational capabilities make all but the bcrypt and sha-crypt families known to be susceptible to exhaustive key searches. The tuneable work factor of the bcrypt and sha-crypt families has allowed them to be set to be more computationally intensive over time. The use of the other families is not recommended at this time, but are maintained for legacy compatibility. >+.Pp >+The first argument to >+.Fn crypt >+is the >+.Fa key >+to hash >+.Pq usually a password , >+as a NUL-terminated string. The second is the >+.Fa salt . >+A salt is a random value that assists in complicating offline recovery. The length and format of the salt, and how it will be used is algorithm dependent. For best results, specify at least sixteen characters of salt. >+.Pp >+If the salt begins with the string >+.Qq $digit , >+then the >+.Sx Modular Crypt Format >+is used. If it begins with an underscore >+.Qq _ , >+then the >+.Sx DES Extended Format >+is used. If the salt is 2 or 13 characters and includes only 0-9, a-z, A-Z a dot . or a slash /, then >+.Sx Traditional DES Format >+is used. If none of these conditions are true, crypt will use the default hash function set by crypt_set_format, >+.Pq or Traditional DES Format if no default has been set, for systems with DES support . >+.Pp >+The >+.Fn crypt_makesalt >+function populates an >+.Fa output >+buffer with a newly generated salt for the specified valid >+.Fa format . >+The size of the pre-allocated buffer is passed via >+.Fa out_len . >+If the output buffer is too small, the required size is set in >+.Fa out_len . >+.Pp >+The >+.Fn crypt_get_format >+function returns a constant string that represents the name of the algorithm set as the default. Its use is deprecated. >+.Pp >+The > .Fn crypt_set_format >-has been called to change the default. >-.Pp >-The first argument to >-.Nm >-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 >-.Bl -tag -width Traditional -compact -offset indent >-.It Extended >-If it begins with an underscore >-.Pq Dq _ >-then the >-.Tn DES >-Extended Format >-is used in interpreting both the key and the salt, as outlined below. >-.It Modular >-If it begins with the string >-.Dq $digit$ >-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 >-.Pq or the first portion . >+function sets the default encoding >+.Fa format >+according to the supplied string. Its use is deprecated. >+.Pp >+The salts, formats, and algorithms are outlined below. >+ >+.Sh Modular Crypt Format >+.Pp >+Modular Crypt Format is the current standard way to describe which algorithm and parameters to use for a particular crypt invocation. Salts that are prefixed with $digit are using the modular crypt format. The prefix selects the algorithm to use. Valid prefixes are: >+.Bl -column -offset indent ".Sy Prefix" ".Sy Algorithm" >+.It Sy Prefix Ta Sy Algorithm >+.It Li $1$ Ta >+.Sx md5-crypt >+.It Li $2 Ta >+.Sx bcrypt >+.It Li $3$ Ta >+.Sx NT-Hash >+.It Li $5$ Ta >+.Sx sha256-crypt >+.It Li $6$ Ta >+.Sx sha512-crypt > .El > .Pp >-All routines are designed to be time-consuming. >-.Ss DES Extended Format: >-The >-.Ar key >-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 >-.Tn DES >-key. >-For each additional group, the XOR of the encryption of the current >-.Tn DES >-key with itself and the group bits becomes the next >-.Tn DES >-key. >-.Pp >-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 >-.Dq ./0-9A-Za-z . >-This allows 24 bits for both >-.Fa count >-and >-.Fa salt . >+Everything following the prefix in the salt parameter is algorithm dependant, but includes things like work factor, and an actual salt >+.Pq random value for that particular invocation . >+ >+.Ss md5-crypt >+.Bl -column ".Sy Output Hash Example:" ".Sy 8 characters from the set [a-zA-Z0-9./]" >+.It Li Format Strings: Ta $1$, md5 >+.It Li Salt Format: Ta 8 characters from the set [a-zA-Z0-9./] >+.It Li Full Salt Example: Ta $1$deadbeef$ >+.It Li Output Hash Example: Ta $1$deadbeef$0Huu6KHrKLVWfqa4WljDE0 >+.El > .Pp >-The >-.Fa salt >-introduces disorder in the >-.Tn DES >-algorithm in one of 16777216 or 4096 possible ways >-.Po >-i.e., with 24 or 12 bits: if bit >-.Em i >-of the >-.Ar salt >-is set, then bits >-.Em i >-and >-.Em i+24 >-are swapped in the >-.Tn DES >-E-box output >-.Pc . >+md5-crypt was the default crypt format in FreeBSD for many years, developed by Poul-Henning Kamp. > .Pp >-The >-.Tn DES >-key is used to encrypt a 64-bit constant using >-.Ar count >-iterations of >-.Tn DES . >-The value returned is a >-.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: >-If the salt begins with the string >-.Fa $digit$ >-then the Modular Crypt Format is used. >-The >-.Fa digit >-represents which algorithm is used in encryption. >-Following the token is >-the actual salt to use in the encryption. >-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: >-.Pp >-.Bl -enum -compact -offset indent >-.It >-MD5 >-.It >-Blowfish >-.It >-NT-Hash >-.It >-(unused) >-.It >-SHA-256 >-.It >-SHA-512 >+It has seen widespread use in many commercial products, and for a long time was good enough. It has a fixed work factor, which means that as computers became faster, the ability to attack it has increased proportionally. >+.Pp >+Its use is no longer recommended. >+ >+.Ss bcrypt >+.Bl -column ".Sy Output Hash Example:" ".Sy $2a$05$CCCCCCCCCCCCCCCCCCCCC.VGOzA784oUp/Z0DY336zx7pLYAy0lwK" >+.It Li Format Strings: Ta $2$[rounds]$, $2a$[rounds]$, $2b$[rounds]$, blf >+.It Li Salt Format: Ta 16 bytes then base-64 encoded from the set [a-zA-Z0-9./] >+.It Li Full Salt Example: Ta $2a$05$CCCCCCCCCCCCCCCCCCCCC. >+.It Li Output Hash Example: Ta $2a$05$CCCCCCCCCCCCCCCCCCCCC.VGOzA784oUp/Z0DY336zx7pLYAy0lwK > .El > .Pp >-Other crypt formats may be easily added. >-An example salt would be: >-.Bl -tag -width 6n -offset indent >-.It Cm "$4$thesalt$rest" >+bcrypt is the first algorithm to support a tuneable work factor. It was initially introduced in OpenBSD, by Niels Provos, based on the Usenix paper "A Future-Adaptable Password Scheme" by Niels Provos and David Mazières. >+.Pp >+There are three variations supported, each with minor bug fixes. 2b is the recommended variation. >+.Pp >+The work factor is specified by the rounds parameter in the format string. These rounds are logarithmic. That is, >+.Qq $2b$08$ >+will take approximately twice as long as >+.Qq $2b$07$ >+for the same salt and key. 04 is the lowest supported work factor, and 31 is the highest. >+.Pp >+When the format string >+.Qq blf >+is specified, it is equivalent to specifying >+.Qq $2b$04$ . >+ >+.Ss NT-Hash >+.Bl -column ".Sy Output Hash Example:" ".Sy $3$sdlksjfdlksjdlfk" >+.It Li Format Strings: Ta $3$, nth >+.It Li Salt Format: Ta no salt >+.It Li Full Salt Example: Ta $3$ >+.It Li Output Hash Example: Ta $3$$cc0fb8a290eebbfe74e7207f2ace5927 > .El >-.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. >-Unless a global default has been specified or >-.Fn crypt_set_format >-has set the format to something else, the built-in default format is >-used. >-This is currently >-.\" >-.\" NOTICE: Also make sure to update this >-.\" >-DES >-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 eight characters of salt. >+nt-hash is supported for compatibility reasons only. It is strongly discouraged for any production uses. >+ >+.Ss sha256-crypt >+.Bl -column ".Sy Output Hash Example:" ".Sy $5$saltstring$5B8vYYiY.CVt1RlTTf8KbXBH3hsxY/GNooZaBBGWEc5, $5$rounds=10000$saltstringsaltst$3xv.VbSHBb41AL9AvLeujZkZRBAwqFMz2.opqey6IcA " >+.It Li Format Strings: Ta $5$, $5$rounds=[rounds]$, sha256 >+.It Li Salt Format: Ta 16 characters from the set [a-zA-Z0-9./] >+.It Li Full Salt Examples: Ta $5$saltstring$, $5$rounds=10000$saltstringsaltst$ >+.It Li Output Hash Examples: Ta $5$saltstring$5B8vYYiY.CVt1RlTTf8KbXBH3hsxY/GNooZaBBGWEc5, $5$rounds=10000$saltstringsaltst$3xv.VbSHBb41AL9AvLeujZkZRBAwqFMz2.opqey6IcA >+.El > .Pp >-The >-.Fn crypt_get_format >-function returns a constant string that represents the name of the >-algorithm currently used. >-Valid values are >-.\" >-.\" NOTICE: Also make sure to update this, too, as well >-.\" >-.Ql des , >-.Ql blf , >-.Ql md5 , >-.Ql sha256 , >-.Ql sha512 >-and >-.Ql nth . >+sha256 supports a tunable work factor. It was developed by Ulrich Drepper of Red Hat, and is detailed in >+.Qq Unix crypt using SHA-256 and SHA-512 . > .Pp >-The >+From that document: >+.Pp >+.Qo >+Security departments in companies are trying to phase out all uses of MD5. They demand a method which is officially sanctioned. For US-based users this means tested by the NIST. >+.Pp >+This rules out the use of another already implemented method with limited spread: the use of the Blowfish encryption method. The choice comes down to tested encryption >+.Pq 3DES, AES >+or hash sums >+.Pq the SHA family . >+.Qc >+.Pp >+The prepositions in the above statement are misleading. Blowfish as a primitive, like 3DES or AES, has stood up to years of scrutinty by the cryptographic communinty. bcrypt, the password hashing function, is ubiquitous. It also currently provides greater resilience against pipe-lined or GPU-based attacks for the approximate same CPU workload as the sha-crypt family, based on its limited memory requirements. This is not expected to remain true with future improvements to GPUs. An additional subtle difference between bcrypt and the sha families is that bcrypt's salt is 2^128 bits, while the sha family is 2^96 bits. >+.Pp >+If you require a algorithm that includes NIST sanctioned primitives, choose one of the sha-crypt methods. >+.Pp >+The work factor is specified by the rounds parameter in the format string. These rounds are linear. That is, >+.Qq $5$rounds=20000$ >+will take approximately twice as long as >+.Qq $5$rounds=10000$ >+for the same salt and key. 1000 is the minimum number of rounds, 999999999 is the maximum. >+.Pp >+When the format string >+.Qq sha256 , >+or >+.Qq $5$ >+is specified, it is equivalent to specifying >+.Qq $5$rounds=5000$ . >+ >+ >+.Ss sha512-crypt >+.Bl -column ".Sy Output Hash Example:" ".Sy $6$saltstring$svn8UoSVapNtMuq1ukKS4tPQd8iKwSMHWjl/O817G3uBnIFNjnQJuesI68u4OTLiBFdcbYEdFCoEOfaS35inz1, $6$rounds=10000$saltstringsaltst$OW1/O6BYHV6BcXZu8QVeXbDWra3Oeqh0sbHbbMCVNSnCM/UrjmM0Dp8vOuZeHBy/YTBmSK6H9qs/y3RnOaw5v." >+.It Li Format Strings: Ta $6$, $6$rounds=[rounds]$, sha512 >+.It Li Salt Format: Ta 16 characters from the set [a-zA-Z0-9./] >+.It Li Full Salt Examples: Ta $6$saltstring$, $6$rounds=10000$saltstringsaltst$ >+.It Li Output Hash Examples: Ta $6$saltstring$svn8UoSVapNtMuq1ukKS4tPQd8iKwSMHWjl/O817G3uBnIFNjnQJuesI68u4OTLiBFdcbYEdFCoEOfaS35inz1, $6$rounds=10000$saltstringsaltst$OW1/O6BYHV6BcXZu8QVeXbDWra3Oeqh0sbHbbMCVNSnCM/UrjmM0Dp8vOuZeHBy/YTBmSK6H9qs/y3RnOaw5v. >+.El >+sha512 is nearly equivalent to sha256, except that it uses SHA512 as a primitive. See Unix crypt using SHA-256 and SHA-512 for more details. >+ >+The details provided in sha256 apply here as well. >+ >+When the format string >+.Qq sha512 , >+or >+.Qq $6$ >+is specified, it is equivalent to specifying >+.Qq $6$rounds=5000$ . >+ >+.Sh DES Extended Format: >+.Pp >+The key 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 DES key as follows: the first group of 56 bits becomes the initial DES key. For each additional group, the XOR of the encryption of the current DES key with itself and the group bits becomes the next DES key. >+.Pp >+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 >+.Qq ./0-9A-Za-z . >+This allows 24 bits for both count and salt. >+.Pp >+The salt introduces disorder in the DES algorithm in one of 16777216 or 4096 possible ways >+.Pq i.e., with 24 or 12 bits: if bit i of the salt is set, then bits i and i+24 are swapped in the DES E-box output . >+.Pp >+The DES key is used to encrypt a 64-bit constant using count iterations of DES. The value returned is a NUL-terminated string, 20 or 13 bytes >+.Pq plus NUL >+in length, consisting of the salt followed by the encoded 64-bit encryption. >+ >+.Sh Traditional DES Format: >+.Pp >+The algorithm used will depend upon whether > .Fn crypt_set_format >-function sets the default encoding format according to the supplied >-.Fa string . >+has been called to set the global default. The built-in default format is used, if no default is set. This is currently >+.Qq des >+if it is available, or >+.Qq sha512 >+if not. >+ > .Sh RETURN VALUES >-The >+.Pp >+The > .Fn crypt >-function returns a pointer to the encrypted value on success, and NULL on >-failure. >-Note: this is not a standard behaviour, AT&T >+function returns a pointer to the encrypted value on success, >+and NULL on failure. Note: this is not a standard behaviour, AT&T > .Fn crypt > will always return a pointer to a string. > .Pp > The >+.Fn crypt_makesalt >+function will return a 0 on success, or non-zero on failure. It may fail in one of two >+ways. If >+.Fa out_len >+has changed, the >+.Fa output >+buffer was not large enough to store the salt. The required size will be stored >+in >+.Fa out_len . >+If >+.Fa out_len >+has not changed, then the >+.Fa format >+passed was invalid. >+.Pp >+The > .Fn crypt_set_format >-function will return 1 if the supplied encoding format was valid. >-Otherwise, a value of 0 is returned. >+function will return 1 if the supplied encoding format was valid. Otherwise, a value of 0 is returned. >+ >+ >+.Sh EXAMPLES >+.Bd -literal >+#include <stdio.h> >+#include <string.h> >+#include <pthread.h> >+ >+#include <pwd.h> >+#include <unistd.h> >+ >+#include <sys/param.h> >+ >+int >+main() >+{ >+ char *global_static_buffer; >+ char final[_PASSWORD_LEN + 1]; >+ char test[_PASSWORD_LEN + 1]; >+ char salt[CRYPT_SALT_MAX_LEN + 1]; >+ size_t salt_sz = sizeof(salt); >+ >+ int exit_code = 0; >+ >+ /* threaded implementations should use a mutex around crypt */ >+ pthread_mutex_t mtx; >+ if (pthread_mutex_init(&mtx, NULL) ) { >+ exit_code = 1; >+ goto exit1; >+ } >+ >+ if (crypt_makesalt(salt, "$2b$08$", &salt_sz) ) { >+ if ( salt_sz != sizeof(salt) ) { >+ printf("Destination buffer too small for algorithm salt\\n"); >+ exit_code = 2; >+ goto exit; >+ } >+ >+ printf("Invalid format specified\\n"); >+ exit_code = 3; >+ goto exit; >+ } >+ printf("crypt_makesalt result: %s\\n", salt); >+ >+ /* >+ * Generate a crypt for storage >+ */ >+ >+ /* crypt buffer is global static */ >+ pthread_mutex_lock(&mtx); >+ global_static_buffer = crypt("you'll never guess me!", salt); >+ strncpy(final, global_static_buffer, sizeof(final) ); >+ pthread_mutex_unlock(&mtx); >+ >+ if (global_static_buffer == NULL) { >+ printf("crypt failed\\n"); >+ exit_code = 4; >+ goto exit; >+ } >+ >+ printf("crypt result: %s\\n", final); >+ >+ /* >+ * Compare a string against a stored crypt >+ */ >+ >+ pthread_mutex_lock(&mtx); >+ global_static_buffer = crypt("is this it?", final); >+ strncpy(test, global_static_buffer, sizeof(test) ); >+ pthread_mutex_unlock(&mtx); >+ >+ if (global_static_buffer == NULL) { >+ printf("second crypt failed\\n"); >+ exit_code = 5; >+ goto exit; >+ } >+ >+ printf("test result: %s\\n", test); >+ >+ /* a timing-safe string compare would be better */ >+ if ( strncmp(test, final, MAX(sizeof(test), sizeof(final) ) ) == 0 ) { >+ printf("The two buffers match.\\n"); >+ } else { >+ printf("The two buffers do not match.\\n"); >+ } >+ >+exit: >+ pthread_mutex_destroy(&mtx); >+exit1: >+ return exit_code; >+} >+.Ed > .Sh SEE ALSO >-.Xr login 1 , >-.Xr passwd 1 , >-.Xr getpass 3 , >-.Xr passwd 5 >+.Xr login 1 , >+.Xr passwd 1 , >+.Xr getpass 3 , >+.Xr login_getcapstr 3 , >+.Xr passwd 5 , >+ > .Sh HISTORY >-A rotor-based >+.Pp >+A rotor-based > .Fn crypt >-function appeared in >-.At v6 . >-The current style >+function appeared in Version 6 AT&T UNIX. The >+current style > .Fn crypt >-first appeared in >-.At v7 . >+first appeared in Version 7 AT&T UNIX. > .Pp >-The >-.Tn DES >-section of the code (FreeSec 1.0) was developed outside the United >-States of America as an unencumbered replacement for the U.S.-only >-.Nx >-libcrypt encryption library. >+The DES section of the code >+.Pq FreeSec 1.0 >+was developed outside the >+United States of America as an unencumbered replacement for the U.S.-only >+NetBSD libcrypt encryption library. >+ > .Sh AUTHORS >-.An -nosplit >-Originally written by >-.An David Burren Aq Mt davidb@werj.com.au , >-later additions and changes by >-.An Poul-Henning Kamp , >-.An Mark R V Murray , >-.An Michael Bretterklieber , >-.An Kris Kennaway , >-.An Brian Feldman , >-.An Paul Herman >-and >-.An Niels Provos . >+Originally written by David Burren >+.Mt davidb@werj.com.au , >+later additions and changes by Poul-Henning Kamp, Mark R V Murray, Michael >+Bretterklieber, Kris Kennaway, Brian Feldman, Paul Herman, Niels Provos, and >+Derek Marcotte. >+ > .Sh BUGS >-The >+The > .Fn crypt >-function returns a pointer to static data, and subsequent calls to >+function returns a pointer to static data, and subsequent >+calls to > .Fn crypt >-will modify the same data. >-Likewise, >+will modify the same data. Likewise, > .Fn crypt_set_format > modifies static data. >+ >+.Sh SECURITY CONSIDERATIONS >+The following algorithms are considered insecure, and are not recommended >+for new implementations: >+.Sx md5-crypt , >+.Sx DES Extended Format , >+.Sx Traditional DES Format , >+and >+.Sx NT-Hash . > .Pp >-The NT-hash scheme does not use a salt, >-and is not hard >-for a competent attacker >-to break. >-Its use is not recommended. >+.Sx bcrypt >+is preferred over >+.Sx sha512-crypt , >+or >+.Sx sha256-crypt , >+because of >+its resiliance to pipelined, and GPU based attacks - unless having a >+NIST-approved algorithm is a requirement. >diff --git a/lib/libcrypt/crypt.c b/lib/libcrypt/crypt.c >index 623809e..c819fef 100644 >--- a/lib/libcrypt/crypt.c >+++ b/lib/libcrypt/crypt.c >@@ -1,6 +1,7 @@ > /*- > * Copyright (c) 1999 Mark Murray > * Copyright (c) 2014 Dag-Erling Smørgrav >+ * Copyright (c) 2015 Derek Marcotte > * All rights reserved. > * > * Redistribution and use in source and binary forms, with or without >@@ -29,56 +30,146 @@ > __FBSDID("$FreeBSD$"); > > #include <sys/types.h> >+#include <sys/param.h> > > #include <libutil.h> > #include <string.h> > #include <unistd.h> >+#include <regex.h> >+#include <stdbool.h> >+#include <stdlib.h> > > #include "crypt.h" > > /* > * List of supported crypt(3) formats. > * >- * The default algorithm is the last entry in the list (second-to-last >- * array element since the last is a sentinel). The reason for placing >- * the default last rather than first is that DES needs to be at the >- * bottom for the algorithm guessing logic in crypt(3) to work correctly, >- * and it needs to be the default for backward compatibility. >+ * Ordered from most probable to least probable[1], for the find algorithm to >+ * preform a little better in some cases. Generally, order is not important. >+ * >+ * 1. as guessed by a random person >+ * > */ > static const struct crypt_format { > const char *const name; > char *(*const func)(const char *, const char *); > const char *const magic; >+ const char *const default_format; >+ const char *const format_regex; >+ >+ const uint8_t salt_bytes; >+ const bool salt_trailing_sign; /* do we tack on a $ at the end of the salt */ > } crypt_formats[] = { >- { "md5", crypt_md5, "$1$" }, >+ { "md5", crypt_md5, "$1$", "$1$", "^\\$1\\$$", 8, true }, >+ { "sha512", crypt_sha512, "$6$", "$6$", "^\\$6\\$(rounds=[0-9]{0,9}\\$)?$", 16, true }, > #ifdef HAS_BLOWFISH >- { "blf", crypt_blowfish, "$2" }, >+ { "blf", crypt_blowfish, "$2", "$2b$04$", "^\\$2[ab]?\\$[0-9]{2}\\$$", 22 /* 16 * 1.333 */, false }, > #endif >- { "nth", crypt_nthash, "$3$" }, >- { "sha256", crypt_sha256, "$5$" }, >- { "sha512", crypt_sha512, "$6$" }, > #ifdef HAS_DES >- { "des", crypt_des, "_" }, >+ { "des", crypt_des, NULL, "", NULL, 2, false }, >+ { "des-ext", crypt_des, "_", "_..T.", "^_[A-Za-z0-9./]{4}$", 4, false }, > #endif >- >+ { "nth", crypt_nthash, "$3$", "$3$", "^\\$3\\$$", 0, false }, >+ { "sha256", crypt_sha256, "$5$", "$5$", "^\\$5\\$(rounds=[0-9]{0,9}\\$)?$", 16, true }, >+ > /* sentinel */ >- { NULL, NULL, NULL } >+ { NULL, NULL, NULL, NULL, NULL, 0, NULL } > }; > >-static const struct crypt_format *crypt_format = >- &crypt_formats[(sizeof crypt_formats / sizeof *crypt_formats) - 2]; >+#ifdef HAS_DES >+/* must be des if system has des */ >+static char default_format[CRYPT_FORMAT_MAX_LEN + 1] = "des"; >+#else >+static char default_format[CRYPT_FORMAT_MAX_LEN + 1] = "sha512"; >+#endif >+ >+/* local-scope only */ >+static const struct crypt_format *crypt_find_format(const char *); >+static bool crypt_validate_format_regex(const char *, const char *); >+static bool crypt_format_is_modular(const char*); > > #define DES_SALT_ALPHABET \ > "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" > > /* >+ * Fill a buffer with a new salt conforming to a particular crypt format >+ * >+ * We're breaking the API convention established by crypt_set_format (return 0 >+ * on success) * because it might be nice to behave like the rest of C >+ * libraries, rather than the one deprecated function. >+ * >+ */ >+int >+crypt_makesalt(char *out, const char *format, size_t *outlen) >+{ >+ const struct crypt_format *cf; >+ uint8_t rand_buf[4]; >+ size_t reqsz; >+ const char *prefix; >+ size_t prefix_len; >+ >+ /* diff really is a size, but keeping it api compatible with b64_from_24bit. >+ * Only up to 4 bytes anyways, shouldn't be a problem, right? >+ */ >+ int diff; >+ unsigned int i; >+ >+ /* find the appropriate format entry */ >+ cf = crypt_find_format(format); >+ if (cf == NULL ) >+ return (-1); >+ >+ /* calculate required output size */ >+ if (crypt_format_is_modular(format) ) { >+ prefix = format; >+ } else { >+ prefix = cf->default_format; >+ } >+ prefix_len = strlen(prefix); >+ reqsz = prefix_len + (size_t) cf->salt_bytes; >+ >+ if (cf->salt_trailing_sign) >+ reqsz++; >+ >+ /* trailing '\0' */ >+ reqsz++; >+ >+ /* does the output buff have enough */ >+ if (reqsz > *outlen) { >+ *outlen = reqsz; >+ return (-2); >+ } >+ >+ /* start building our output */ >+ strncpy(out, prefix, *outlen); >+ out += prefix_len; >+ >+ for (i = 0; i < cf->salt_bytes; i += 4 ) { >+ arc4random_buf(rand_buf, 3); >+ >+ diff = MIN(cf->salt_bytes - i, 4); >+ b64_from_24bit(rand_buf[2], rand_buf[1], rand_buf[0], diff, &diff, &out); >+ } >+ >+ /* cleanup */ >+ bzero(rand_buf, sizeof(rand_buf) ); >+ >+ if (cf->salt_trailing_sign) { >+ out[0] = '$'; >+ out++; >+ } >+ >+ /* don't need to add trailing '\0', strncpy above will have set it already */ >+ return (0); >+} >+ >+/* > * Returns the name of the currently selected format. > */ > const char * > crypt_get_format(void) > { >- >- return (crypt_format->name); >+ return default_format; > } > > /* >@@ -87,15 +178,75 @@ crypt_get_format(void) > int > crypt_set_format(const char *format) > { >- const struct crypt_format *cf; >+ if (crypt_find_format(format) == NULL) { >+ return (0); >+ } >+ >+ strncpy(default_format, format, sizeof(default_format) ); >+ return (1); >+} >+ >+/* >+ * is the crypt format a recognized as valid >+ */ >+static bool >+crypt_format_validate_regex(const char* regex, const char *format) >+{ >+ regex_t regex_c; >+ int res = 0; >+ >+ /* We could cache these, but they are simple, and this function won't be >+ * called often. >+ */ >+ if (regcomp(®ex_c, regex, REG_EXTENDED) != 0) { >+ return false; >+ } >+ >+ res = regexec(®ex_c, format, 0, NULL, 0); >+ regfree(®ex_c); >+ >+ return !res; >+} >+ >+/* >+ * is the crypt format a fancy-dancy modular format >+ */ >+static bool >+crypt_format_is_modular(const char* format) >+{ >+ /* we'll treat 'new des' as modular, because they can set 24 bits of count via salt */ >+ return (format[0] == '$' || format[0] == '_'); >+} > >- for (cf = crypt_formats; cf->name != NULL; ++cf) { >- if (strcasecmp(cf->name, format) == 0) { >- crypt_format = cf; >- return (1); >+/* >+ * lookup our format in our internal table for a matching crypt_format structure >+ */ >+static const struct crypt_format * >+crypt_find_format(const char *format) >+{ >+ const struct crypt_format *cf; >+ >+ if (strcmp(format, "default") == 0 ) { >+ format = default_format; >+ } >+ >+ if (crypt_format_is_modular(format) ) { >+ /* modular crypt magic lookup, force full syntax */ >+ for (cf = crypt_formats; cf->name != NULL; ++cf) { >+ if (cf->magic != NULL && strstr(format, cf->magic) == format && crypt_format_validate_regex(cf->format_regex, format) ) { >+ return cf; >+ } >+ } >+ } else { >+ /* name lookup */ >+ for (cf = crypt_formats; cf->name != NULL; ++cf) { >+ if (strcasecmp(cf->name, format) == 0) { >+ return cf; >+ } > } > } >- return (0); >+ >+ return NULL; > } > > /* >@@ -110,14 +261,19 @@ crypt(const char *passwd, const char *salt) > #ifdef HAS_DES > int len; > #endif >- >+ >+ /* use the magic in the salt for lookup */ > 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 >+ /* check if it's standard des */ > len = strlen(salt); > if ((len == 13 || len == 2) && strspn(salt, DES_SALT_ALPHABET) == len) > return (crypt_des(passwd, salt)); > #endif >- return (crypt_format->func(passwd, salt)); >+ >+ cf = crypt_find_format(default_format); >+ return (cf->func(passwd, salt)); > } >diff --git a/lib/libcrypt/tests/crypt_tests.c b/lib/libcrypt/tests/crypt_tests.c >index 426d10e..42bcf8f 100644 >--- a/lib/libcrypt/tests/crypt_tests.c >+++ b/lib/libcrypt/tests/crypt_tests.c >@@ -4,6 +4,7 @@ __FBSDID("$FreeBSD$"); > #include <sys/types.h> > #include <crypt.h> > #include <unistd.h> >+#include <stdio.h> > > #include <atf-c.h> > >@@ -12,7 +13,6 @@ __FBSDID("$FreeBSD$"); > ATF_TC(md5); > ATF_TC_HEAD(md5, tc) > { >- > atf_tc_set_md_var(tc, "descr", "Tests the MD5 based password hash"); > } > >@@ -25,14 +25,13 @@ ATF_TC_BODY(md5, tc) > ATF_CHECK_STREQ(pw, want); > } > >-ATF_TC(invalid); >-ATF_TC_HEAD(invalid, tc) >+ATF_TC(md5invalid); >+ATF_TC_HEAD(md5invalid, tc) > { >- >- atf_tc_set_md_var(tc, "descr", "Tests that invalid password fails"); >+ atf_tc_set_md_var(tc, "descr", "Tests that md5invalid password fails"); > } > >-ATF_TC_BODY(invalid, tc) >+ATF_TC_BODY(md5invalid, tc) > { > const char want[] = "$1$cafebabe$0Huu6KHrKLVWfqa4WljDE0"; > char *pw; >@@ -41,14 +40,396 @@ ATF_TC_BODY(invalid, tc) > ATF_CHECK(strcmp(pw, want) != 0); > } > >+ATF_TC(sha256_vector_1); >+ATF_TC_HEAD(sha256_vector_1, tc) >+{ >+ atf_tc_set_md_var(tc, "descr", "Test vector from crypt-sha256.c"); >+} >+ >+ATF_TC_BODY(sha256_vector_1, tc) >+{ >+ const char want[] = "$5$saltstring$5B8vYYiY.CVt1RlTTf8KbXBH3hsxY/GNooZaBBGWEc5"; >+ char *pw; >+ >+ pw = crypt("Hello world!", "$5$saltstring"); >+ ATF_CHECK_STREQ(pw, want); >+} >+ >+ATF_TC(sha256_invalid); >+ATF_TC_HEAD(sha256_invalid, tc) >+{ >+ atf_tc_set_md_var(tc, "descr", "Tests that an invalid password fails"); >+} >+ >+ATF_TC_BODY(sha256_invalid, tc) >+{ >+ const char want[] = "$5$saltstring$5B8vYYiY.CVt1RlTTf8KbXBH3hsxY/GNooZaBBGWEc5"; >+ char *pw; >+ >+ pw = crypt("Goodbye cruel world!", "$5$saltstring"); >+ ATF_CHECK(strcmp(pw, want) != 0); >+} >+ >+ATF_TC(sha256_vector_2); >+ATF_TC_HEAD(sha256_vector_2, tc) >+{ >+ atf_tc_set_md_var(tc, "descr", "Test vector from crypt-sha256.c"); >+} >+ >+ATF_TC_BODY(sha256_vector_2, tc) >+{ >+ const char want[] = "$5$rounds=10000$saltstringsaltst$3xv.VbSHBb41AL9AvLeujZkZRBAwqFMz2." >+ "opqey6IcA"; >+ char *pw; >+ >+ pw = crypt("Hello world!", "$5$rounds=10000$saltstringsaltstring"); >+ ATF_CHECK_STREQ(pw, want); >+} >+ >+ATF_TC(sha256_vector_3); >+ATF_TC_HEAD(sha256_vector_3, tc) >+{ >+ atf_tc_set_md_var(tc, "descr", "Test vector from crypt-sha256.c"); >+} >+ >+ATF_TC_BODY(sha256_vector_3, tc) >+{ >+ const char want[] = "$5$rounds=5000$toolongsaltstrin$Un/5jzAHMgOGZ5.mWJpuVolil07guHPvOW8" >+ "mGRcvxa5"; >+ char *pw; >+ >+ pw = crypt("This is just a test", "$5$rounds=5000$toolongsaltstring"); >+ ATF_CHECK_STREQ(pw, want); >+} >+ >+ATF_TC(sha256_vector_4); >+ATF_TC_HEAD(sha256_vector_4, tc) >+{ >+ atf_tc_set_md_var(tc, "descr", "Test vector from crypt-sha256.c"); >+} >+ >+ATF_TC_BODY(sha256_vector_4, tc) >+{ >+ const char want[] = "$5$rounds=1400$anotherlongsalts$Rx.j8H.h8HjEDGomFU8bDkXm3XIUnzyxf12" >+ "oP84Bnq1"; >+ char *pw; >+ >+ pw = crypt("a very much longer text to encrypt. This one even stretches over more" >+ "than one line.", "$5$rounds=1400$anotherlongsaltstring"); >+ ATF_CHECK_STREQ(pw, want); >+} >+ >+ATF_TC(sha256_vector_5); >+ATF_TC_HEAD(sha256_vector_5, tc) >+{ >+ atf_tc_set_md_var(tc, "descr", "Test vector from crypt-sha256.c"); >+} >+ >+ATF_TC_BODY(sha256_vector_5, tc) >+{ >+ const char want[] = "$5$rounds=77777$short$JiO1O3ZpDAxGJeaDIuqCoEFysAe1mZNJRs3pw0KQRd/"; >+ char *pw; >+ >+ pw = crypt("we have a short salt string but not a short password", "$5$rounds=77777$short"); >+ ATF_CHECK_STREQ(pw, want); >+} >+ >+ATF_TC(sha256_vector_6); >+ATF_TC_HEAD(sha256_vector_6, tc) >+{ >+ atf_tc_set_md_var(tc, "descr", "Test vector from crypt-sha256.c"); >+} >+ >+ATF_TC_BODY(sha256_vector_6, tc) >+{ >+ const char want[] = "$5$rounds=123456$asaltof16chars..$gP3VQ/6X7UUEW3HkBn2w1/Ptq2jxPyzV/" >+ "cZKmF/wJvD"; >+ char *pw; >+ >+ pw = crypt("a short string", "$5$rounds=123456$asaltof16chars.."); >+ ATF_CHECK_STREQ(pw, want); >+} >+ >+ATF_TC(sha256_vector_7); >+ATF_TC_HEAD(sha256_vector_7, tc) >+{ >+ atf_tc_set_md_var(tc, "descr", "Test vector from crypt-sha256.c"); >+} >+ >+ATF_TC_BODY(sha256_vector_7, tc) >+{ >+ const char want[] = "$5$rounds=1000$roundstoolow$yfvwcWrQ8l/K0DAWyuPMDNHpIVlTQebY9l/gL97" >+ "2bIC"; >+ char *pw; >+ >+ pw = crypt("the minimum number is still observed", "$5$rounds=10$roundstoolow"); >+ ATF_CHECK_STREQ(pw, want); >+} >+ >+ATF_TC(sha512_vector_1); >+ATF_TC_HEAD(sha512_vector_1, tc) >+{ >+ atf_tc_set_md_var(tc, "descr", "Test vector from crypt-sha512.c"); >+} >+ >+ATF_TC_BODY(sha512_vector_1, tc) >+{ >+ const char want[] = "$6$saltstring$svn8UoSVapNtMuq1ukKS4tPQd8iKwSMHWjl/O817G3uBnIFNjnQJu" >+ "esI68u4OTLiBFdcbYEdFCoEOfaS35inz1"; >+ char *pw; >+ >+ pw = crypt("Hello world!", "$6$saltstring"); >+ ATF_CHECK_STREQ(pw, want); >+} >+ >+ATF_TC(sha512_invalid); >+ATF_TC_HEAD(sha512_invalid, tc) >+{ >+ atf_tc_set_md_var(tc, "descr", "Test vector from crypt-sha512.c"); >+} >+ >+ATF_TC_BODY(sha512_invalid, tc) >+{ >+ const char want[] = "$6$saltstring$svn8UoSVapNtMuq1ukKS4tPQd8iKwSMHWjl/O817G3uBnIFNjnQJu" >+ "esI68u4OTLiBFdcbYEdFCoEOfaS35inz1"; >+ char *pw; >+ >+ pw = crypt("Goodbye cruel world!", "$6$saltstring"); >+ ATF_CHECK(strcmp(pw, want) != 0); >+} >+ >+ATF_TC(sha512_vector_2); >+ATF_TC_HEAD(sha512_vector_2, tc) >+{ >+ atf_tc_set_md_var(tc, "descr", "Test vector from crypt-sha512.c"); >+} >+ >+ATF_TC_BODY(sha512_vector_2, tc) >+{ >+ const char want[] = "$6$rounds=10000$saltstringsaltst$OW1/O6BYHV6BcXZu8QVeXbDWra3Oeqh0sb" >+ "HbbMCVNSnCM/UrjmM0Dp8vOuZeHBy/YTBmSK6H9qs/y3RnOaw5v."; >+ char *pw; >+ >+ pw = crypt("Hello world!", "$6$rounds=10000$saltstringsaltstring"); >+ ATF_CHECK_STREQ(pw, want); >+} >+ >+ATF_TC(sha512_vector_3); >+ATF_TC_HEAD(sha512_vector_3, tc) >+{ >+ atf_tc_set_md_var(tc, "descr", "Test vector from crypt-sha512.c"); >+} >+ >+ATF_TC_BODY(sha512_vector_3, tc) >+{ >+ const char want[] = "$6$rounds=5000$toolongsaltstrin$lQ8jolhgVRVhY4b5pZKaysCLi0QBxGoNeKQ" >+ "zQ3glMhwllF7oGDZxUhx1yxdYcz/e1JSbq3y6JMxxl8audkUEm0"; >+ char *pw; >+ >+ pw = crypt("This is just a test", "$6$rounds=5000$toolongsaltstring"); >+ ATF_CHECK_STREQ(pw, want); >+} >+ >+ATF_TC(sha512_vector_4); >+ATF_TC_HEAD(sha512_vector_4, tc) >+{ >+ atf_tc_set_md_var(tc, "descr", "Test vector from crypt-sha512.c"); >+} >+ >+ATF_TC_BODY(sha512_vector_4, tc) >+{ >+ const char want[] = "$6$rounds=1400$anotherlongsalts$POfYwTEok97VWcjxIiSOjiykti.o/pQs.wP" >+ "vMxQ6Fm7I6IoYN3CmLs66x9t0oSwbtEW7o7UmJEiDwGqd8p4ur1"; >+ char *pw; >+ >+ pw = crypt("a very much longer text to encrypt. This one even stretches over more" >+ "than one line.", "$6$rounds=1400$anotherlongsaltstring"); >+ ATF_CHECK_STREQ(pw, want); >+} >+ >+ATF_TC(sha512_vector_5); >+ATF_TC_HEAD(sha512_vector_5, tc) >+{ >+ atf_tc_set_md_var(tc, "descr", "Test vector from crypt-sha512.c"); >+} >+ >+ATF_TC_BODY(sha512_vector_5, tc) >+{ >+ const char want[] = "$6$rounds=77777$short$WuQyW2YR.hBNpjjRhpYD/ifIw05xdfeEyQoMxIXbkvr0g" >+ "ge1a1x3yRULJ5CCaUeOxFmtlcGZelFl5CxtgfiAc0"; >+ char *pw; >+ >+ pw = crypt("we have a short salt string but not a short password", "$6$rounds=77777$short"); >+ ATF_CHECK_STREQ(pw, want); >+} >+ >+ATF_TC(sha512_vector_6); >+ATF_TC_HEAD(sha512_vector_6, tc) >+{ >+ atf_tc_set_md_var(tc, "descr", "Test vector from crypt-sha512.c"); >+} >+ >+ATF_TC_BODY(sha512_vector_6, tc) >+{ >+ const char want[] = "$6$rounds=123456$asaltof16chars..$BtCwjqMJGx5hrJhZywWvt0RLE8uZ4oPwc" >+ "elCjmw2kSYu.Ec6ycULevoBK25fs2xXgMNrCzIMVcgEJAstJeonj1"; >+ char *pw; >+ >+ pw = crypt("a short string", "$6$rounds=123456$asaltof16chars.."); >+ ATF_CHECK_STREQ(pw, want); >+} >+ >+ATF_TC(sha512_vector_7); >+ATF_TC_HEAD(sha512_vector_7, tc) >+{ >+ atf_tc_set_md_var(tc, "descr", "Test vector from crypt-sha512.c"); >+} >+ >+ATF_TC_BODY(sha512_vector_7, tc) >+{ >+ const char want[] = "$6$rounds=1000$roundstoolow$kUMsbe306n21p9R.FRkW3IGn.S9NPN0x50YhH1x" >+ "hLsPuWGsUSklZt58jaTfF4ZEQpyUNGc0dqbpBYYBaHHrsX."; >+ char *pw; >+ >+ pw = crypt("the minimum number is still observed", "$6$rounds=10$roundstoolow"); >+ ATF_CHECK_STREQ(pw, want); >+} >+ >+#ifdef HAS_BLOWFISH >+ATF_TC(blf_vector_1); >+ATF_TC_HEAD(blf_vector_1, tc) >+{ >+ atf_tc_set_md_var(tc, "descr", "Solar Designer wrapper.c test vector 1"); >+} >+ >+ATF_TC_BODY(blf_vector_1, tc) >+{ >+ const char want[] = "$2a$05$CCCCCCCCCCCCCCCCCCCCC.E5YPO9kmyuRGyh0XouQYb4YMJKvyOeW"; >+ char *pw; >+ >+ pw = crypt("U*U", want); >+ ATF_CHECK_STREQ(pw, want); >+} >+ >+ >+ATF_TC(blf_invalid); >+ATF_TC_HEAD(blf_invalid, tc) >+{ >+ atf_tc_set_md_var(tc, "descr", "Solar Designer wrapper.c test vector 1 - invalid"); >+} >+ >+ATF_TC_BODY(blf_invalid, tc) >+{ >+ const char want[] = "$2a$05$CCCCCCCCCCCCCCCCCCCCC.E5YPO9kmyuRGyh0XouQYb4YMJKvyOeW"; >+ char *pw; >+ >+ pw = crypt("ME*ME", want); >+ ATF_CHECK(strcmp(pw, want) != 0); >+} >+ >+ATF_TC(blf_vector_2); >+ATF_TC_HEAD(blf_vector_2, tc) >+{ >+ atf_tc_set_md_var(tc, "descr", "Solar Designer wrapper.c test vector 2"); >+} >+ >+ATF_TC_BODY(blf_vector_2, tc) >+{ >+ const char want[] = "$2a$05$CCCCCCCCCCCCCCCCCCCCC.VGOzA784oUp/Z0DY336zx7pLYAy0lwK"; >+ char *pw; >+ >+ pw = crypt("U*U*", want); >+ ATF_CHECK_STREQ(pw, want); >+} >+ >+ATF_TC(blf_vector_3); >+ATF_TC_HEAD(blf_vector_3, tc) >+{ >+ atf_tc_set_md_var(tc, "descr", "Solar Designer wrapper.c test vector 3 - long password"); >+} >+ >+ATF_TC_BODY(blf_vector_3, tc) >+{ >+ const char want[] = "$2a$05$abcdefghijklmnopqrstuu5s2v8.iXieOjg/.AySBTTZIIVFJeBui"; >+ char *pw; >+ >+ pw = crypt("0123456789abcdefghijklmnopqrstuvwxyz" >+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" >+ "chars after 72 are ignored", want); >+ ATF_CHECK_STREQ(pw, want); >+} >+ >+ATF_TC(blf_vector_4); >+ATF_TC_HEAD(blf_vector_4, tc) >+{ >+ atf_tc_set_md_var(tc, "descr", "Solar Designer wrapper.c test vector 4"); >+} >+ >+ATF_TC_BODY(blf_vector_4, tc) >+{ >+ const char want[] = "$2b$05$/OK.fbVrR/bpIqNJ5ianF.CE5elHaaO4EbggVDjb8P19RukzXSM3e"; >+ char *pw; >+ >+ pw = crypt("\xff\xff\xa3", want); >+ ATF_CHECK_STREQ(pw, want); >+} >+ >+ATF_TC(blf_vector_5); >+ATF_TC_HEAD(blf_vector_5, tc) >+{ >+ atf_tc_set_md_var(tc, "descr", "Solar Designer wrapper.c test vector 5 - ensure our $2a$05$ matches the $2y$05$"); >+} >+ >+ATF_TC_BODY(blf_vector_5, tc) >+{ >+ const char want[] = "$2a$05$/OK.fbVrR/bpIqNJ5ianF.nRht2l/HRhr6zmCp9vYUvvsqynflf9e"; >+ char *pw; >+ >+ pw = crypt("\xff\xa3" "345", want); >+ ATF_CHECK_STREQ(pw, want); >+} >+ >+#endif >+ > /* > * This function must not do anything except enumerate > * the test cases, per atf-c-api(3). > */ > ATF_TP_ADD_TCS(tp) > { >- > ATF_TP_ADD_TC(tp, md5); >- ATF_TP_ADD_TC(tp, invalid); >+ ATF_TP_ADD_TC(tp, md5invalid); >+ >+ ATF_TP_ADD_TC(tp, sha256_vector_1); >+ ATF_TP_ADD_TC(tp, sha256_invalid); >+ ATF_TP_ADD_TC(tp, sha256_vector_2); >+ ATF_TP_ADD_TC(tp, sha256_vector_3); >+ ATF_TP_ADD_TC(tp, sha256_vector_4); >+/* >+ ATF_TP_ADD_TC(tp, sha256_vector_5); >+ ATF_TP_ADD_TC(tp, sha256_vector_6); >+*/ >+ ATF_TP_ADD_TC(tp, sha256_vector_7); >+ >+ ATF_TP_ADD_TC(tp, sha512_vector_1); >+ ATF_TP_ADD_TC(tp, sha512_invalid); >+ ATF_TP_ADD_TC(tp, sha512_vector_2); >+ ATF_TP_ADD_TC(tp, sha512_vector_3); >+ ATF_TP_ADD_TC(tp, sha512_vector_4); >+/* >+ ATF_TP_ADD_TC(tp, sha512_vector_5); >+ ATF_TP_ADD_TC(tp, sha512_vector_6); >+*/ >+ ATF_TP_ADD_TC(tp, sha512_vector_7); >+ >+#ifdef HAS_BLOWFISH >+ ATF_TP_ADD_TC(tp, blf_vector_1); >+ ATF_TP_ADD_TC(tp, blf_invalid); >+ ATF_TP_ADD_TC(tp, blf_vector_2); >+ ATF_TP_ADD_TC(tp, blf_vector_3); >+ ATF_TP_ADD_TC(tp, blf_vector_4); >+ ATF_TP_ADD_TC(tp, blf_vector_5); >+#endif >+ > return atf_no_error(); > } >diff --git a/lib/libpam/modules/pam_unix/pam_unix.c b/lib/libpam/modules/pam_unix/pam_unix.c >index 5403d5d..283a821 100644 >--- a/lib/libpam/modules/pam_unix/pam_unix.c >+++ b/lib/libpam/modules/pam_unix/pam_unix.c >@@ -67,17 +67,11 @@ __FBSDID("$FreeBSD$"); > #include <security/pam_modules.h> > #include <security/pam_mod_misc.h> > >-#define PASSWORD_HASH "md5" > #define DEFAULT_WARN (2L * 7L * 86400L) /* Two weeks */ >-#define SALTSIZE 32 > > #define LOCKED_PREFIX "*LOCKED*" > #define LOCKED_PREFIX_LEN (sizeof(LOCKED_PREFIX) - 1) > >-static void makesalt(char []); >- >-static char password_hash[] = PASSWORD_HASH; >- > #define PAM_OPT_LOCAL_PASS "local_pass" > #define PAM_OPT_NIS_PASS "nis_pass" > >@@ -269,13 +263,15 @@ pam_sm_chauthtok(pam_handle_t *pamh, int flags, > struct ypclnt *ypclnt; > const void *yp_domain, *yp_server; > #endif >- char salt[SALTSIZE + 1]; >+ char salt[CRYPT_SALT_MAX_LEN + 1]; >+ size_t salt_sz; > login_cap_t *lc; > struct passwd *pwd, *old_pwd; > const char *user, *old_pass, *new_pass; > char *encrypted; > time_t passwordtime; > int pfd, tfd, retval; >+ const char *passwd_format; > > if (openpam_get_option(pamh, PAM_OPT_AUTH_AS_SELF)) > user = getlogin(); >@@ -379,10 +375,21 @@ pam_sm_chauthtok(pam_handle_t *pamh, int flags, > return (PAM_BUF_ERR); > > lc = login_getclass(pwd->pw_class); >- if (login_setcryptfmt(lc, password_hash, NULL) == NULL) >- openpam_log(PAM_LOG_ERROR, >- "can't set password cipher, relying on default"); > >+ salt_sz = sizeof(salt); >+ passwd_format = login_getcapstr(lc, "passwd_format", "", NULL); >+ if (crypt_makesalt(salt, passwd_format, &salt_sz) ) { >+ login_close(lc); >+ >+ if (salt_sz == sizeof(salt) ) { >+ PAM_LOG("Unable to create salt for crypt(3) format: %s", passwd_format); >+ } else { >+ PAM_LOG("Not enough space in buffer to create salt for format: %s. CRYPT_SALT_MAX_LEN is wrong. Buffer size: %zu, required: %zu", passwd_format, sizeof(salt), salt_sz); >+ } >+ >+ return (PAM_SERVICE_ERR); >+ } >+ > /* set password expiry date */ > pwd->pw_change = 0; > passwordtime = login_getcaptime(lc, "passwordtime", 0, 0); >@@ -390,7 +397,6 @@ pam_sm_chauthtok(pam_handle_t *pamh, int flags, > pwd->pw_change = time(NULL) + passwordtime; > > login_close(lc); >- makesalt(salt); > pwd->pw_passwd = crypt(new_pass, salt); > #ifdef YP > switch (old_pwd->pw_fields & _PWF_SOURCE) { >@@ -446,33 +452,4 @@ pam_sm_chauthtok(pam_handle_t *pamh, int flags, > return (retval); > } > >-/* Mostly stolen from passwd(1)'s local_passwd.c - markm */ >- >-static unsigned char itoa64[] = /* 0 ... 63 => ascii - 64 */ >- "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; >- >-static void >-to64(char *s, long v, int n) >-{ >- while (--n >= 0) { >- *s++ = itoa64[v&0x3f]; >- v >>= 6; >- } >-} >- >-/* Salt suitable for traditional DES and MD5 */ >-static void >-makesalt(char salt[SALTSIZE + 1]) >-{ >- int i; >- >- /* These are not really random numbers, they are just >- * numbers that change to thwart construction of a >- * dictionary. >- */ >- for (i = 0; i < SALTSIZE; i += 4) >- to64(&salt[i], arc4random(), 4); >- salt[SALTSIZE] = '\0'; >-} >- > PAM_MODULE_ENTRY("pam_unix"); >diff --git a/lib/libutil/login.conf.5 b/lib/libutil/login.conf.5 >index 1c3cfee..11fbc55 100644 >--- a/lib/libutil/login.conf.5 >+++ b/lib/libutil/login.conf.5 >@@ -278,7 +278,14 @@ multiplied by 5 seconds. > allowed before the login fails. > .It "passwd_format string sha512 The encryption format that new or" > changed passwords will use. >-Valid values include "des", "md5", "blf", "sha256" and "sha512"; see >+Valid values include Modular Crypt Format strings, >+.Qq des , >+.Qq md5 , >+.Qq blf , >+.Qq sha256 >+and >+.Qq sha512 ; >+see > .Xr crypt 3 > for details. > NIS clients using a >diff --git a/lib/libutil/login_cap.3 b/lib/libutil/login_cap.3 >index 9421718..adbf585 100644 >--- a/lib/libutil/login_cap.3 >+++ b/lib/libutil/login_cap.3 >@@ -569,6 +569,13 @@ If calling > on the specifier fails, > .Fa error > is returned to indicate this. >+.Fn login_setcryptfmt >+and >+.Xr crypt_set_format 3 >+are both deprecated in favour of >+.Xr login_getcapstr 3 >+and >+.Xr crypt_makesalt 3 . > .El > .Sh SEE ALSO > .Xr login 1 , >diff --git a/usr.sbin/pw/pw.h b/usr.sbin/pw/pw.h >index 592d592..fbb8d937 100644 >--- a/usr.sbin/pw/pw.h >+++ b/usr.sbin/pw/pw.h >@@ -97,7 +97,7 @@ char const *boolean_str(int val); > char *newstr(char const * p); > > void pw_log(struct userconf * cnf, int mode, int which, char const * fmt,...) __printflike(4, 5); >-char *pw_pwcrypt(char *password); >+char *pw_pwcrypt(const char *password, const char *format); > > extern const char *Modes[]; > extern const char *Which[]; >diff --git a/usr.sbin/pw/pw_group.c b/usr.sbin/pw/pw_group.c >index 834160f..41e821c 100644 >--- a/usr.sbin/pw/pw_group.c >+++ b/usr.sbin/pw/pw_group.c >@@ -91,7 +91,7 @@ grp_set_passwd(struct group *grp, bool update, int fd, bool precrypted) > errx(EX_DATAERR, "wrong encrypted passwrd"); > grp->gr_passwd = line; > } else >- grp->gr_passwd = pw_pwcrypt(line); >+ grp->gr_passwd = pw_pwcrypt(line, "default"); > } > > int >diff --git a/usr.sbin/pw/pw_user.c b/usr.sbin/pw/pw_user.c >index 75e7fb6..9fc537a 100644 >--- a/usr.sbin/pw/pw_user.c >+++ b/usr.sbin/pw/pw_user.c >@@ -78,10 +78,11 @@ static char *pw_homepolicy(struct userconf * cnf, char *homedir, > const char *user); > static char *pw_shellpolicy(struct userconf * cnf); > static char *pw_password(struct userconf * cnf, char const * user, >- bool dryrun); >+ char const * format, bool dryrun); > static char *shell_path(char const * path, char *shells[], char *sh); > static void rmat(uid_t uid); > static void rmopie(char const * name); >+static void copy_passwd_format(char *passwd_format, login_cap_t *lc, size_t max); > > static void > mkdir_home_parents(int dfd, const char *dir) >@@ -176,6 +177,7 @@ pw_set_passwd(struct passwd *pwd, int fd, bool precrypted, bool update) > login_cap_t *lc; > char line[_PASSWORD_LEN+1]; > char *p; >+ char passwd_format[CRYPT_FORMAT_MAX_LEN + 1]; > > if (fd == '-') { > if (!pwd->pw_passwd || *pwd->pw_passwd != '*') { >@@ -221,15 +223,36 @@ pw_set_passwd(struct passwd *pwd, int fd, bool precrypted, bool update) > pwd->pw_passwd = strdup(line); > } else { > lc = login_getpwclass(pwd); >- if (lc == NULL || >- login_setcryptfmt(lc, "sha512", NULL) == NULL) >- warn("setting crypt(3) format"); >+ copy_passwd_format(passwd_format, lc, sizeof(passwd_format) ); > login_close(lc); >- pwd->pw_passwd = pw_pwcrypt(line); >+ pwd->pw_passwd = pw_pwcrypt(line, passwd_format); > } > return (1); > } > >+void >+copy_passwd_format(char *passwd_format, login_cap_t *lc, size_t max) { >+ const char *cap; >+ const char *def = "sha512"; >+ >+ if (lc == NULL) { >+ warn("setting crypt(3) format"); >+ strncpy(passwd_format, def, max); >+ return; >+ } >+ >+ >+ cap = login_getcapstr(lc, "passwd_format", def, NULL); >+ if (cap == NULL) { >+ warn("setting crypt(3) format"); >+ strncpy(passwd_format, def, max); >+ return; >+ } >+ >+ strncpy(passwd_format, cap, max); >+ return; >+} >+ > static void > perform_chgpwent(const char *name, struct passwd *pwd, char *nispasswd) > { >@@ -479,24 +502,22 @@ pw_shellpolicy(struct userconf * cnf) > return shell_path(cnf->shelldir, cnf->shells, cnf->shell_default); > } > >-#define SALTSIZE 32 >- >-static char const chars[] = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ./"; >- >-char * >-pw_pwcrypt(char *password) >+char * >+pw_pwcrypt(const char *password, const char *format) > { >- int i; >- char salt[SALTSIZE + 1]; >+ char salt[CRYPT_SALT_MAX_LEN + 1]; >+ size_t salt_sz = sizeof(salt); > char *cryptpw; >- static char buf[256]; >+ static char buf[_PASSWORD_LEN + 1]; > >- /* >- * Calculate a salt value >- */ >- for (i = 0; i < SALTSIZE; i++) >- salt[i] = chars[arc4random_uniform(sizeof(chars) - 1)]; >- salt[SALTSIZE] = '\0'; >+ if (crypt_makesalt(salt, format, &salt_sz) ) { >+ if (salt_sz == sizeof(salt) ) { >+ errx(EX_CONFIG, "Unable to create salt for crypt(3) format: %s", format); >+ } else { >+ /* really shouldn't get here */ >+ errx(EX_CONFIG, "Not enough space to write salt to buffer. CRYPT_SALT_MAX_LEN is wrong."); >+ } >+ } > > cryptpw = crypt(password, salt); > if (cryptpw == NULL) >@@ -505,8 +526,9 @@ pw_pwcrypt(char *password) > } > > static char * >-pw_password(struct userconf * cnf, char const * user, bool dryrun) >+pw_password(struct userconf * cnf, char const * user, const char * format, bool dryrun) > { >+ static char const chars[] = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ./!@#$%^&*()-+=<>?"; > int i, l; > char pwbuf[32]; > >@@ -539,7 +561,7 @@ pw_password(struct userconf * cnf, char const * user, bool dryrun) > strlcpy(pwbuf, user, sizeof(pwbuf)); > break; > } >- return pw_pwcrypt(pwbuf); >+ return pw_pwcrypt(pwbuf, format); > } > > static int >@@ -1185,6 +1207,7 @@ pw_user_add(int argc, char **argv, char *arg1) > int rc, ch, fd = -1; > size_t i; > bool dryrun, nis, pretty, quiet, createhome, precrypted, genconf; >+ char passwd_format[CRYPT_FORMAT_MAX_LEN + 1]; > > dryrun = nis = pretty = quiet = createhome = precrypted = false; > genconf = false; >@@ -1367,10 +1390,9 @@ pw_user_add(int argc, char **argv, char *arg1) > pwd->pw_dir = pw_homepolicy(cmdcnf, homedir, pwd->pw_name); > pwd->pw_shell = pw_shellpolicy(cmdcnf); > lc = login_getpwclass(pwd); >- if (lc == NULL || login_setcryptfmt(lc, "sha512", NULL) == NULL) >- warn("setting crypt(3) format"); >+ copy_passwd_format(passwd_format, lc, sizeof(passwd_format)); > login_close(lc); >- pwd->pw_passwd = pw_password(cmdcnf, pwd->pw_name, dryrun); >+ pwd->pw_passwd = pw_password(cmdcnf, pwd->pw_name, passwd_format, dryrun); > if (pwd->pw_uid == 0 && strcmp(pwd->pw_name, "root") != 0) > warnx("WARNING: new account `%s' has a uid of 0 " > "(superuser access!)", pwd->pw_name); >@@ -1497,6 +1519,7 @@ pw_user_mod(int argc, char **argv, char *arg1) > bool precrypted; > mode_t homemode = 0; > time_t expire_days, password_days, now; >+ char passwd_format[CRYPT_FORMAT_MAX_LEN + 1]; > > expire_days = password_days = -1; > gecos = homedir = grname = name = newname = skel = shell =NULL; >@@ -1714,12 +1737,11 @@ pw_user_mod(int argc, char **argv, char *arg1) > > if (passwd && conf.fd == -1) { > lc = login_getpwclass(pwd); >- if (lc == NULL || login_setcryptfmt(lc, "sha512", NULL) == NULL) >- warn("setting crypt(3) format"); >+ copy_passwd_format(passwd_format, lc, sizeof(passwd_format) ); > login_close(lc); > cnf->default_password = passwd_val(passwd, > cnf->default_password); >- pwd->pw_passwd = pw_password(cnf, pwd->pw_name, dryrun); >+ pwd->pw_passwd = pw_password(cnf, pwd->pw_name, passwd_format, dryrun); > edited = true; > } >
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 182518
:
137124
|
152839
|
154251
|
154265
|
173187
| 173188