diff options
-rw-r--r-- | manual/contrib.texi | 2 | ||||
-rw-r--r-- | manual/crypt.texi | 234 | ||||
-rw-r--r-- | manual/examples/genpass.c | 59 | ||||
-rw-r--r-- | manual/examples/testpass.c | 67 | ||||
-rw-r--r-- | manual/users.texi | 4 |
5 files changed, 25 insertions, 341 deletions
diff --git a/manual/contrib.texi b/manual/contrib.texi index 20d9f74780..52ebd6944a 100644 --- a/manual/contrib.texi +++ b/manual/contrib.texi @@ -199,7 +199,7 @@ Romain Geissler for various fixes. @item Michael Glad for the passphrase-hashing function @code{crypt} and related -functions. +functions (no longer part of glibc, but we still appreciate his work). @item Wolfram Gloger for contributing the memory allocation functions diff --git a/manual/crypt.texi b/manual/crypt.texi index af23dd7847..4882ee34e5 100644 --- a/manual/crypt.texi +++ b/manual/crypt.texi @@ -1,205 +1,18 @@ @node Cryptographic Functions, Debugging Support, System Configuration, Top @chapter Cryptographic Functions -@c %MENU% Passphrase storage and strongly unpredictable bytes. +@c %MENU% A few functions to support cryptographic applications -@Theglibc{} includes only a few special-purpose cryptographic -functions: one-way hash functions for passphrase storage, and access -to a cryptographic randomness source, if one is provided by the -operating system. Programs that need general-purpose cryptography -should use a dedicated cryptography library, such as +@Theglibc{} includes only one type of special-purpose cryptographic +functions; these allow use of a source of cryptographically strong +pseudorandom numbers, if such a source is provided by the operating +system. Programs that need general-purpose cryptography should use +a dedicated cryptography library, such as @uref{https://www.gnu.org/software/libgcrypt/,,libgcrypt}. -Many countries place legal restrictions on the import, export, -possession, or use of cryptographic software. We deplore these -restrictions, but we must still warn you that @theglibc{} may be -subject to them, even if you do not use the functions in this chapter -yourself. The restrictions vary from place to place and are changed -often, so we cannot give any more specific advice than this warning. - @menu -* Passphrase Storage:: One-way hashing for passphrases. * Unpredictable Bytes:: Randomness for cryptographic purposes. @end menu -@node Passphrase Storage -@section Passphrase Storage -@cindex passphrase hashing -@cindex one-way hashing -@cindex hashing, passphrase - -Sometimes it is necessary to be sure that a user is authorized -to use some service a machine provides---for instance, to log in as a -particular user id (@pxref{Users and Groups}). One traditional way of -doing this is for each user to choose a secret @dfn{passphrase}; then, the -system can ask someone claiming to be a user what the user's passphrase -is, and if the person gives the correct passphrase then the system can -grant the appropriate privileges. (Traditionally, these were called -``passwords,'' but nowadays a single word is too easy to guess.) - -Programs that handle passphrases must take special care not to reveal -them to anyone, no matter what. It is not enough to keep them in a -file that is only accessible with special privileges. The file might -be ``leaked'' via a bug or misconfiguration, and system administrators -shouldn't learn everyone's passphrase even if they have to edit that -file for some reason. To avoid this, passphrases should also be -converted into @dfn{one-way hashes}, using a @dfn{one-way function}, -before they are stored. - -A one-way function is easy to compute, but there is no known way to -compute its inverse. This means the system can easily check -passphrases, by hashing them and comparing the result with the stored -hash. But an attacker who discovers someone's passphrase hash can -only discover the passphrase it corresponds to by guessing and -checking. The one-way functions are designed to make this process -impractically slow, for all but the most obvious guesses. (Do not use -a word from the dictionary as your passphrase.) - -@Theglibc{} provides an interface to four one-way functions, based on -the SHA-2-512, SHA-2-256, MD5, and DES cryptographic primitives. New -passphrases should be hashed with either of the SHA-based functions. -The others are too weak for newly set passphrases, but we continue to -support them for verifying old passphrases. The DES-based hash is -especially weak, because it ignores all but the first eight characters -of its input. - -@deftypefun {char *} crypt (const char *@var{phrase}, const char *@var{salt}) -@standards{X/Open, unistd.h} -@standards{GNU, crypt.h} -@safety{@prelim{}@mtunsafe{@mtasurace{:crypt}}@asunsafe{@asucorrupt{} @asulock{} @ascuheap{} @ascudlopen{}}@acunsafe{@aculock{} @acsmem{}}} -@c Besides the obvious problem of returning a pointer into static -@c storage, the DES initializer takes an internal lock with the usual -@c set of problems for AS- and AC-Safety. -@c The NSS implementations may leak file descriptors if cancelled. -@c The MD5, SHA256 and SHA512 implementations will malloc on long keys, -@c and NSS relies on dlopening, which brings about another can of worms. - -The function @code{crypt} converts a passphrase string, @var{phrase}, -into a one-way hash suitable for storage in the user database. The -string that it returns will consist entirely of printable ASCII -characters. It will not contain whitespace, nor any of the characters -@samp{:}, @samp{;}, @samp{*}, @samp{!}, or @samp{\}. - -The @var{salt} parameter controls which one-way function is used, and -it also ensures that the output of the one-way function is different -for every user, even if they have the same passphrase. This makes it -harder to guess passphrases from a large user database. Without salt, -the attacker could make a guess, run @code{crypt} on it once, and -compare the result with all the hashes. Salt forces the attacker to -make separate calls to @code{crypt} for each user. - -To verify a passphrase, pass the previously hashed passphrase as the -@var{salt}. To hash a new passphrase for storage, set @var{salt} to a -string consisting of a prefix plus a sequence of randomly chosen -characters, according to this table: - -@multitable @columnfractions .2 .1 .3 -@headitem One-way function @tab Prefix @tab Random sequence -@item SHA-2-512 -@tab @samp{$6$} -@tab 16 characters -@item SHA-2-256 -@tab @samp{$5$} -@tab 16 characters -@item MD5 -@tab @samp{$1$} -@tab 8 characters -@item DES -@tab @samp{} -@tab 2 characters -@end multitable - -In all cases, the random characters should be chosen from the alphabet -@code{./0-9A-Za-z}. - -With all of the hash functions @emph{except} DES, @var{phrase} can be -arbitrarily long, and all eight bits of each byte are significant. -With DES, only the first eight characters of @var{phrase} affect the -output, and the eighth bit of each byte is also ignored. - -@code{crypt} can fail. Some implementations return @code{NULL} on -failure, and others return an @emph{invalid} hashed passphrase, which -will begin with a @samp{*} and will not be the same as @var{salt}. In -either case, @code{errno} will be set to indicate the problem. Some -of the possible error codes are: - -@table @code -@item EINVAL -@var{salt} is invalid; neither a previously hashed passphrase, nor a -well-formed new salt for any of the supported hash functions. - -@item EPERM -The system configuration forbids use of the hash function selected by -@var{salt}. - -@item ENOMEM -Failed to allocate internal scratch storage. - -@item ENOSYS -@itemx EOPNOTSUPP -Hashing passphrases is not supported at all, or the hash function -selected by @var{salt} is not supported. @Theglibc{} does not use -these error codes, but they may be encountered on other operating -systems. -@end table - -@code{crypt} uses static storage for both internal scratchwork and the -string it returns. It is not safe to call @code{crypt} from multiple -threads simultaneously, and the string it returns will be overwritten -by any subsequent call to @code{crypt}. - -@code{crypt} is specified in the X/Open Portability Guide and is -present on nearly all historical Unix systems. However, the XPG does -not specify any one-way functions. - -@code{crypt} is declared in @file{unistd.h}. @Theglibc{} also -declares this function in @file{crypt.h}. -@end deftypefun - -@deftypefun {char *} crypt_r (const char *@var{phrase}, const char *@var{salt}, struct crypt_data *@var{data}) -@standards{GNU, crypt.h} -@safety{@prelim{}@mtsafe{}@asunsafe{@asucorrupt{} @asulock{} @ascuheap{} @ascudlopen{}}@acunsafe{@aculock{} @acsmem{}}} -@tindex struct crypt_data -@c Compared with crypt, this function fixes the @mtasurace:crypt -@c problem, but nothing else. - -The function @code{crypt_r} is a thread-safe version of @code{crypt}. -Instead of static storage, it uses the memory pointed to by its -@var{data} argument for both scratchwork and the string it returns. -It can safely be used from multiple threads, as long as different -@var{data} objects are used in each thread. The string it returns -will still be overwritten by another call with the same @var{data}. - -@var{data} must point to a @code{struct crypt_data} object allocated -by the caller. All of the fields of @code{struct crypt_data} are -private, but before one of these objects is used for the first time, -it must be initialized to all zeroes, using @code{memset} or similar. -After that, it can be reused for many calls to @code{crypt_r} without -erasing it again. @code{struct crypt_data} is very large, so it is -best to allocate it with @code{malloc} rather than as a local -variable. @xref{Memory Allocation}. - -@code{crypt_r} is a GNU extension. It is declared in @file{crypt.h}, -as is @code{struct crypt_data}. -@end deftypefun - -The following program shows how to use @code{crypt} the first time a -passphrase is entered. It uses @code{getentropy} to make the salt as -unpredictable as possible; @pxref{Unpredictable Bytes}. - -@smallexample -@include genpass.c.texi -@end smallexample - -The next program demonstrates how to verify a passphrase. It checks a -hash hardcoded into the program, because looking up real users' hashed -passphrases may require special privileges (@pxref{User Database}). -It also shows that different one-way functions produce different -hashes for the same passphrase. - -@smallexample -@include testpass.c.texi -@end smallexample - @node Unpredictable Bytes @section Generating Unpredictable Bytes @cindex randomness source @@ -211,27 +24,24 @@ hashes for the same passphrase. @cindex CSPRNG @cindex DRBG -Cryptographic applications often need some random data that will be as -difficult as possible for a hostile eavesdropper to guess. For -instance, encryption keys should be chosen at random, and the ``salt'' -strings used by @code{crypt} (@pxref{Passphrase Storage}) should also -be chosen at random. - -Some pseudo-random number generators do not provide unpredictable-enough -output for cryptographic applications; @pxref{Pseudo-Random Numbers}. -Such applications need to use a @dfn{cryptographic random number -generator} (CRNG), also sometimes called a @dfn{cryptographically strong -pseudo-random number generator} (CSPRNG) or @dfn{deterministic random -bit generator} (DRBG). +Cryptographic applications often need random data that will be as +difficult as possible for a hostile eavesdropper to guess. +The pseudo-random number generators provided by @theglibc{} +(@pxref{Pseudo-Random Numbers}) are not suitable for this purpose. +They produce output that is @emph{statistically} random, but fails to +be @emph{unpredictable}. Cryptographic applications require a +@dfn{cryptographic random number generator} (CRNG), also known as a +@dfn{cryptographically strong pseudo-random number generator} (CSPRNG) +or a @dfn{deterministic random bit generator} (DRBG). Currently, @theglibc{} does not provide a cryptographic random number -generator, but it does provide functions that read random data from a -@dfn{randomness source} supplied by the operating system. The -randomness source is a CRNG at heart, but it also continually -``re-seeds'' itself from physical sources of randomness, such as -electronic noise and clock jitter. This means applications do not need -to do anything to ensure that the random numbers it produces are -different on each run. +generator, but it does provide functions that read cryptographically +strong random data from a @dfn{randomness source} supplied by the +operating system. This randomness source is a CRNG at heart, but it +also continually ``re-seeds'' itself from physical sources of +randomness, such as electronic noise and clock jitter. This means +applications do not need to do anything to ensure that the random +numbers it produces are different on each run. The catch, however, is that these functions will only produce relatively short random strings in any one call. Often this is not a diff --git a/manual/examples/genpass.c b/manual/examples/genpass.c deleted file mode 100644 index e40efc782b..0000000000 --- a/manual/examples/genpass.c +++ /dev/null @@ -1,59 +0,0 @@ -/* Encrypting Passwords - Copyright (C) 1991-2023 Free Software Foundation, Inc. - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; either version 2 - of the License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, see <https://www.gnu.org/licenses/>. -*/ - -#include <stdio.h> -#include <unistd.h> -#include <crypt.h> - -int -main(void) -{ - unsigned char ubytes[16]; - char salt[20]; - const char *const saltchars = - "./0123456789ABCDEFGHIJKLMNOPQRST" - "UVWXYZabcdefghijklmnopqrstuvwxyz"; - char *hash; - int i; - - /* Retrieve 16 unpredictable bytes from the operating system. */ - if (getentropy (ubytes, sizeof ubytes)) - { - perror ("getentropy"); - return 1; - } - - /* Use them to fill in the salt string. */ - salt[0] = '$'; - salt[1] = '5'; /* SHA-256 */ - salt[2] = '$'; - for (i = 0; i < 16; i++) - salt[3+i] = saltchars[ubytes[i] & 0x3f]; - salt[3+i] = '\0'; - - /* Read in the user's passphrase and hash it. */ - hash = crypt (getpass ("Enter new passphrase: "), salt); - if (!hash || hash[0] == '*') - { - perror ("crypt"); - return 1; - } - - /* Print the results. */ - puts (hash); - return 0; -} diff --git a/manual/examples/testpass.c b/manual/examples/testpass.c deleted file mode 100644 index 555fe115c4..0000000000 --- a/manual/examples/testpass.c +++ /dev/null @@ -1,67 +0,0 @@ -/* Verify a passphrase. - Copyright (C) 1991-2023 Free Software Foundation, Inc. - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; either version 2 - of the License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, see <https://www.gnu.org/licenses/>. -*/ - -#include <stdio.h> -#include <string.h> -#include <unistd.h> -#include <crypt.h> - -/* @samp{GNU's Not Unix} hashed using SHA-256, MD5, and DES. */ -static const char hash_sha[] = - "$5$DQ2z5NHf1jNJnChB$kV3ZTR0aUaosujPhLzR84Llo3BsspNSe4/tsp7VoEn6"; -static const char hash_md5[] = "$1$A3TxDv41$rtXVTUXl2LkeSV0UU5xxs1"; -static const char hash_des[] = "FgkTuF98w5DaI"; - -int -main(void) -{ - char *phrase; - int status = 0; - - /* Prompt for a passphrase. */ - phrase = getpass ("Enter passphrase: "); - - /* Compare against the stored hashes. Any input that begins with - @samp{GNU's No} will match the DES hash, but the other two will - only match @samp{GNU's Not Unix}. */ - - if (strcmp (crypt (phrase, hash_sha), hash_sha)) - { - puts ("SHA: not ok"); - status = 1; - } - else - puts ("SHA: ok"); - - if (strcmp (crypt (phrase, hash_md5), hash_md5)) - { - puts ("MD5: not ok"); - status = 1; - } - else - puts ("MD5: ok"); - - if (strcmp (crypt (phrase, hash_des), hash_des)) - { - puts ("DES: not ok"); - status = 1; - } - else - puts ("DES: ok"); - - return status; -} diff --git a/manual/users.texi b/manual/users.texi index 72da3fb714..4c83f12c42 100644 --- a/manual/users.texi +++ b/manual/users.texi @@ -1731,8 +1731,8 @@ most systems, but on some systems a special network server gives access to it. Historically, this database included one-way hashes of user -passphrases (@pxref{Passphrase Storage}) as well as public information -about each user (such as their user ID and full name). Many of the +passphrases, as well as public information about each user +(such as their user ID and full name). Many of the names of functions and data structures associated with this database, and the filename @file{/etc/passwd} itself, reflect this history. However, the information in this database is available to all users, and it is |