Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Password Hashing: Basic crypt Usage

We have seen in the previous part of the exercise that hardcoding passwords in plain text in a program is a bad idea. More generally, storing passwords anywhere in clear should be avoided at all cost: if an attacker manage to get read access to the passwords (e.g. through reverse engineering or leaking database content -- something that happens quite often), it's basically game over.

Password Hashing

Storing hashed passwords addresses the aforementioned issue. The idea is as follows: when the password is created, it is not directly stored in plain text in the program or database. Instead, a hash function, such as MD5, SHA-256, etc., is applied on the password, and it is the resulting hash that is stored:

The hash function is made in such a way that, even if what's stored (the hash) becomes accessible to an attacker, it is very hard to revert the hash into the original password. Here, very hard is defined as difficult in terms of computational time. In the third and last part of the exercise, we'll attempt to revert hashes into their original password values, and we'll see that with properly defined passwords it is not feasible.

Hashing only the password is not a good security practice, because an attacker can easily use pre-computed databases of hashes and corresponding passwords (rainbow tables) to crack the password. To avoid that problem, upon creation each password is slightly modified before being hashed: a random value is added (e.g. concatenated) to the password, and that value is different for each password created. That value is called a salt, and will be stored (in clear) alongside the hash value, to be later retrieved for authentication:

crypt(3)

crypt, also called crypt(3) to avoid confusion with an unrelated tool, is a C function used to compute the hash of a password attempt entered by a user. It can be used to create password, but also for authentication, to compute the hash of a password attempt, which can then be compared to the correct password's hash to authenticate the user. The function's prototype is as follows:

char *crypt(const char *key, const char *salt);

The first parameter key is a string representing the password/password attempt for which we want to compute the hash. The second parameter salt is another string that indicate 1) the hash function to use and 2) the salt to combine to the password to produce the final hash. The format for salt is: $<hash function identifier>$<salt>. You can find a list of identifiers here, e.g. use 1 for MD5 or 6 for SHA-512.

Using crypt(3) to Build a Basic Authenticator

This is the skeleton for our basic authenticator:

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <crypt.h>  // needed to use crypt()

#define PASSWORD_HASH // TODO complete here with the correct password in the
                      // format expected by crypt:
                      // <hash function id>$<salt>$<hash of the correct password>

int main() {
    char attempt[100];
    char *hashed_attempt;
    
    printf("Please input your password: \n");
    char *r = fgets(attempt, sizeof(attempt), stdin);
    if(!r)
        return -1; // problem with fgets
    
    // remove the carriage return character from the attempt string
    attempt[strcspn(attempt, "\n")] = 0;

    // TODO complete here:
    // 1. Call crypt to compute the password attempt hash
    // 2. Call strcmp to compare it to the ground truth (PASSWORD_HASH)
    // 3. Use printf to print "Authentication successful!\n" if the correct
    //    password was entered, or "Wrong password.\n" if not

    return 0;
}

Copy-paste this code in a C file and complete the two locations marked as TODOs. An easy way to generate the correct value for PASSWORD_HASH is to use the mkpasswd tool (install it with sudo apt install whois). For example, to generate the hash string for a password value of password, using SHA-512 and a salt value of saltsalt:

mkpasswd --method=SHA-512 --salt=saltsalt password                  
$6$saltsalt$qFmFH.bQmmtXzyBY0s9v7Oicd2z4XSIecDzlB5KiA2/jctKu9YterLp8wwnSq.qc.eoxqOmSuNp2xS0ktL3nh/

To compile the authenticator, make sure to link against libcrypt as follows:

gcc authenticator.c -o authenticator -lcrypt

Before submitting your code, please set the value of PASSWORD_HASH so that the password is your University username (not the numeric ID), the salt is saltsalt, and the hash method is SHA-512.

Submission

Add and push your completed authenticator's source code as a single file named authenticator.c to the submission git repository.