在 C 語言中使用 crypt 函式

Jinku Hu 2023年1月30日 2021年2月28日
  1. 使用 crypt 函式對密碼進行雜湊儲存
  2. 使用嚴格的錯誤處理例程來保證 crypt 函式的成功執行
在 C 語言中使用 crypt 函式

本文將介紹幾種在 C 語言中使用 crypt 函式的方法。

使用 crypt 函式對密碼進行雜湊儲存

crypt 實際上是一個由四個函式組成的系列,提供了用於系統儲存或認證的口令雜湊方法。請注意,這些函式不適合用於通用的加密雜湊,因為與通用函式相比,密碼短語雜湊需要昂貴的計算成本,而通用函式的設計是快速的,使用較少的處理能力。

crypt 接受兩個 char*引數,作為 const 限定引數傳遞。第一個引數指向需要雜湊的口令,第二個引數是稱為 setting 的特殊字串,應該使用 crypt_gensalt 函式生成。setting 引數為 crypt 函式提供了多個引數,如使用哪種雜湊演算法、雜湊的計算成本(越大的值對應成本越高)和隨機鹽位元組。注意,鹽的位元組必須是加密隨機的,它們可以從系統專用的隨機數生成實用程式中單獨獲得。下面的例子演示了特殊值–null 指標作為第三個引數傳遞給 crypt_gensalt 的情況,以表示自動檢索隨機位元組。

有多種雜湊演算法可供選擇(在這個 page 上有詳細介紹),它們作為唯一的字串識別符號傳遞給 crypt_gensalt 函式。一旦 crypt_gensalt 返回 setting 字串,它就可以和密碼一起傳遞給 crypt 函式,返回值將是可列印的 ASCII 文字的雜湊密碼。在接下來的示例程式碼中,我們使用 bcrypt 演算法,識別為"2b$"字首字串。請注意,crypt_gensalt 函式的第二個引數指定了雜湊生成的成本,值 0 指定了給定演算法的預設級別。在本例中,我們指定 15,這是 bcrypt 雜湊演算法的推薦值。

#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "crypt.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);
}

輸出:

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

使用嚴格的錯誤處理例程來保證 crypt 函式的成功執行

前面的示例程式碼從使用者那裡獲取輸入字串,並分配動態記憶體來儲存它,因此,我們需要確保在讀取字串時,stdio 緩衝區中沒有任何剩餘的字元。因此,我們需要確保在讀取字串時,stdio 緩衝區中沒有任何剩餘的字元。為此,我們在 stdout 上呼叫 fflush,然後呼叫 fgets 從使用者那裡獲取輸入字串。另外,注意檢查所有庫函式和系統呼叫的錯誤返回值,並呼叫 perror 輸出相應的資訊。

#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "crypt.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);
}

輸出:

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