vendredi 23 avril 2010

Linux Ubuntu's password management with SHA512

Ubuntu Karmic 9.10 uses now SHA512 algorithm to hash users passwords (instead of DES or MD5). This article describes utilise à présent l'algorithme SHA512 pour le hashage de ses mots de passe (à la place de DES ou MD5). This article describes the implementation of this encryption method in shadow library of Ubuntu.
French version available on the site.

let's roll out the breadcrumb...

passwd command

In Ubuntu Karmic 9.10, users change passwords with "passwd" command.

Have a look to source code of file /src/passwd.c in shadow-* package [1]:
/*
* Authenticate the user. The user will be prompted for their own
* password.
*/
(...)
cipher = pw_encrypt (clear, crypt_passwd);
(...)
the pw_encrypt function is defined in file lib/encrypt.c
char *pw_encrypt (const char *clear, const char *salt)
{
(...)
cp = crypt (clear, salt);
(...)
At this stage, we know that passwd command calls the function crypt().
Crypt() takes as arguments the password in plain text given by the user, and a salt. We'll see later that the salt describes the encryption algortihm chosen.

Who is this salt built?

the default encryption method is sha512

By default, Ubuntu Karmic 9.10 uses sha512 to encrypt its passwords [2]. Indeed, here is an excerpt of the file /etc/logins.def:

$ cat /etc/login.defs
(…)
#
# If set to MD5 , MD5-based algorithm will be used for encrypting password
# If set to SHA256, SHA256-based algorithm will be used for encrypting password
# If set to SHA512, SHA512-based algorithm will be used for encrypting password
# If set to DES, DES-based algorithm will be used for encrypting password (default)
# Overrides the MD5_CRYPT_ENAB option
#
# Note: It is recommended to use a value consistent with
# the PAM modules configuration.
#
ENCRYPT_METHOD SHA512
This file contains the environment variable ENCRYPT_METHOD with value SHA512.

the salt is built with a prefix defined by the environment variable ENCRYPT_METHOD


On one hand, the environment variable ENCRYPT_METHOD is checked in the function Main() from source passwd.c previously listed:
if ((method = getdef_str ("ENCRYPT_METHOD")) == NULL) {
if (!getdef_bool ("MD5_CRYPT_ENAB")) {
pass_max_len = getdef_num ("PASS_MAX_LEN", 8);
}
} else {
if ( (strcmp (method, "MD5") == 0)
#ifdef USE_SHA_CRYPT
|| (strcmp (method, "SHA256") == 0)
|| (strcmp (method, "SHA512") == 0)
#endif /* USE_SHA_CRYPT */
)
(...)
}
The variable data "method" in structure « new_password » is initialised with « SHA512 » (still in passwd.c):
static int new_password (const struct passwd *pw)
{
(...)
char *method;
On the other hand, a new password is created in function Main() of passwd.c, with the help of functions pw_encrypt (previously seen) and crypt_make_salt:
/*
* Encrypt the password, then wipe the cleartext password.
*/
cp = pw_encrypt (pass, crypt_make_salt (NULL, NULL));
memzero (pass, sizeof pass);
The function crypt_make_salt is defined in shadow-*/libmisc/salt.c. The authentication method is there checked:
const char *method;
(…)
{
method = getdef_str ("ENCRYPT_METHOD");
if (NULL == method) {
method = getdef_bool ("MD5_CRYPT_ENAB") ? "MD5" : "DES";
}
You can see that it the environment variable ENCRYPT_METHOD was not defined, MD5_CRYPT_ENAB would be then checked.

Then, with SHA512, the function crypt_make_salt makes a salt with the concatenation of characters '$','6','$ ' and a pseudo random number. It then returns this string as result.
if (0 == strcmp (method, "SHA512")) {
MAGNUM(result, '6');
strcat(result, SHA_salt_rounds((int *)arg));
salt_len = SHA_salt_size();

crypt() from libc choses the hash algorithm according to the salt

Have a look to crypt().

What is the version of glibc?
$ ls /lib/libc-*
/lib/libc-2.11.1.so
Download glibc library sources on website gnu.org [3]. The function crypt() is defined in file crypt/crypt-entry.c:
char * crypt (key, salt)
const char *key;
const char *salt;
{
#ifdef _LIBC
/* Try to find out whether we have to use MD5 encryption replacement. */
if (strncmp (md5_salt_prefix, salt, sizeof (md5_salt_prefix) - 1) == 0)
return __md5_crypt (key, salt);

/* Try to find out whether we have to use SHA256 encryption replacement. */
if (strncmp (sha256_salt_prefix, salt, sizeof (sha256_salt_prefix) - 1) == 0)
return __sha256_crypt (key, salt);

/* Try to find out whether we have to use SHA512 encryption replacement. */
if (strncmp (sha512_salt_prefix, salt, sizeof (sha512_salt_prefix) - 1) == 0)
return __sha512_crypt (key, salt);
#endif

return __crypt_r (key, salt, &_ufc_foobar);
}

Conclusion

We excaped now the forest. We found that Ubuntu Karmic uses sha512 by default, through the environment variable ENCRYPT_METHOD in file /etc/login.defs.

The passwd command is defined in source src/passwd.c in library shadow-*. Passwd wreates a hash with plain text password entered by the user in shell. Passwd calls function pw_encrypt(plain,salt).

this salt is created by function crypt_make_salt() from source shadow-*/libmisc/salt.c. This function uses the environment variable ENCRYPT_METHOD.

The function pw_encrypt of passwd calls function crypt from libc library.

The function crypt choses the encryption method according to salt prefix.

John the Ripper does not support SHA512 yet.

references

1) details of package passwd Ubuntu - http://packages.ubuntu.com/karmic/passwd
2) manual libc – function crypt() - http://www.gnu.org/s/libc/manual/html_node/crypt.html
3) sources libc - http://www.gnu.org/software/libc/

Aucun commentaire:

Publier un commentaire