How to Use the crypt Function in C

Jinku Hu Feb 02, 2024
  1. Use the crypt Function to Hash Passphrases for Storage
  2. Use Strict Error Handling Routines to Guarantee Successful Execution of crypt Functions
How to Use the crypt Function in C

This article will explain several methods of how to use the crypt function in C.

Use the crypt Function to Hash Passphrases for Storage

crypt is actually a family of four functions that provide the passphrase hashing methods for storage on the system or authentication. Note that these functions are not suitable for general-purpose cryptographic hashing since passphrase hashing needs to be computationally expensive compared to general-purpose ones designed to be fast and use less processing power.

crypt takes two char* arguments passed as const qualified parameters. The first argument points to the passphrase that needs to be hashed, and the second one is the special string called setting, that should be generated using the crypt_gensalt function. setting argument provides multiple parameters for the crypt function such as which hashing algorithm to use, the computational cost of the hash (the larger value corresponding to the more costly one) and random salt bytes. Notice that bytes for salt must be cryptographically random, and they can be obtained separately from the system-specific random number generation utilities. The following example demonstrates the case where the special value - null pointer is passed to the crypt_gensalt as the third parameter to indicate automatic retrieval of random bytes.

There are multiple hash algorithms available (fully detailed on this page), and they are passed as unique string identifiers to the crypt_gensalt function. Once the crypt_gensalt returns the setting string, it can be passed to the crypt function along with the passphrase, and the return value will be the hashed passphrase which is printable ASCII text. We use bcrypt algorithm identified as "$2b$" prefix string in the next sample code. Notice that the second argument of the crypt_gensalt function specifies how costly hash generation should be with the value 0 specifying the given algorithm’s default level. In this case, we specify 15, which is the recommended value for the bcrypt hashing algorithm.

#include "crypt.h"
#include "stdio.h"
#include "stdlib.h"
#include "string.h"

enum { MAX_LEN = 1024 };

int main(int argc, char *argv[]) {
  char *text, *encrypted, *salt;
  size_t len;
  long lnmax;

  text = malloc(MAX_LEN);

  printf("Input string to be hashed: ");
  if (fgets(text, MAX_LEN, stdin) == NULL) exit(EXIT_FAILURE);

  len = strlen(text);
  if (text[len - 1] == '\n') text[len - 1] = '\0';

  salt = crypt_gensalt("$2b$", 15, NULL, 0);
  encrypted = crypt(text, salt);

  printf("Encrypted: %s", encrypted);

  free(text);
  exit(EXIT_SUCCESS);
}

Output:

Input string to be hashed: hello there
Encrypted: $2b$15$DkpZq2vJRQoBiK4slxfFa.Eml8PUtFB7CYYH1RJH6XML3ujhX8fqy

Use Strict Error Handling Routines to Guarantee Successful Execution of crypt Functions

The previous example code takes input string from the user and allocates dynamic memory to store it. Thus, we need to ensure the string is read without any leftover characters in the stdio buffer. For this, we call fflush on stdout and then call fgets to take the input string from the user. Also, mind checking all library functions and system calls for their error return values and call perror to output the corresponding message.

#include "crypt.h"
#include "stdio.h"
#include "stdlib.h"
#include "string.h"

enum { MAX_LEN = 1024 };

int main(int argc, char *argv[]) {
  char *text, *encrypted, *salt;
  size_t len;
  long lnmax;

  text = malloc(MAX_LEN);
  if (text == NULL) {
    perror("malloc");
    exit(EXIT_FAILURE);
  }

  printf("Input string to be hashed: ");
  fflush(stdout);
  if (fgets(text, MAX_LEN, stdin) == NULL) exit(EXIT_FAILURE);

  len = strlen(text);
  if (text[len - 1] == '\n') text[len - 1] = '\0';

  salt = crypt_gensalt("$2b$", 15, NULL, 0);
  if (salt == NULL) {
    perror("crypt_gensalt");
    exit(EXIT_FAILURE);
  }

  encrypted = crypt(text, salt);
  if (encrypted == NULL) {
    perror("crypt_gensalt");
    exit(EXIT_FAILURE);
  }

  printf("Encrypted: %s", encrypted);

  free(text);
  exit(EXIT_SUCCESS);
}

Output:

Input string to be hashed: hello there
Encrypted: $2b$15$DkpZq2vJRQoBiK4slxfFa.Eml8PUtFB7CYYH1RJH6XML3ujhX8fqy
Author: Jinku Hu
Jinku Hu avatar Jinku Hu avatar

Founder of DelftStack.com. Jinku has worked in the robotics and automotive industries for over 8 years. He sharpened his coding skills when he needed to do the automatic testing, data collection from remote servers and report creation from the endurance test. He is from an electrical/electronics engineering background but has expanded his interest to embedded electronics, embedded programming and front-/back-end programming.

LinkedIn Facebook