You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++中crypt函数返回不同字符串或无返回的问题排查

问题分析与解决方案

嘿,我帮你找出代码里的几个关键问题啦,正是这些问题导致crypt函数要么生成不同哈希,要么干脆无返回结果,咱们一步步拆解并修复:

1. 动态内存分配的低级错误

不管是readFromTerminal还是generateSalt函数,你调用realloc的时候每次只分配1字节内存——这完全不够存储输入的字符串或者生成的salt,会直接导致内存溢出,触发未定义行为(比如程序崩溃、哈希值乱跳)。

举个例子,readFromTerminal里的错误写法:

realloc(input, (sizeof (char))); // 只分配1字节,根本存不下多个字符

正确的做法是每次根据当前已输入的字符数,分配足够的内存,而且要保存realloc的返回值(它可能返回新的内存地址):

char* temp = (char*)realloc(input, (length + 2) * sizeof(char));
if (temp == NULL) {
    printf("Could not allocate memory!");
    free(input); // 先释放旧内存,避免泄漏
    exit(1);
}
input = temp;

generateSalt里的realloc也要做同样的修正。

2. Salt格式完全不符合crypt的要求

这是最核心的问题!crypt函数的salt不是随便的字符串,它必须遵循特定的格式才能让函数识别哈希算法,否则要么用过时的DES算法(只认前2个字符),要么直接返回NULL。

比如常用的SHA-512算法,salt格式是$6$<salt内容>$,其中<salt内容>最多16个字符,而且只能包含[a-zA-Z0-9./]这些字符。你之前生成的21个任意字符(还包含!@#$%^&*),crypt根本无法识别,自然会乱输出。

修正后的generateSalt应该生成符合规范的salt:

char* generateSalt() {
    const char alphanum[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz./";
    int saltLen = 16; // SHA-512允许的最大salt长度
    char* salt = (char*)malloc(3 + saltLen + 2); // 预留$6$ + salt + $ + \0的空间
    if (salt == NULL) {
        printf("Could not allocate memory!");
        exit(1);
    }
    strcpy(salt, "$6$"); // 指定用SHA-512算法
    srand(time(NULL));
    for (int i = 0; i < saltLen; i++) {
        salt[3 + i] = alphanum[rand() % (sizeof(alphanum)-1)];
    }
    salt[3 + saltLen] = '$';
    salt[3 + saltLen + 1] = '\0';
    return salt;
}

3. crypt返回值的处理错误

你先给hash分配了30字节内存,然后直接用crypt的返回值覆盖它——这不仅造成了内存泄漏,还完全没必要,因为crypt返回的是指向静态内存的指针,不需要你手动分配。另外,一定要检查crypt的返回值,如果是NULL说明出错了,得处理这种情况:

char* hash = crypt(password, salt);
if (hash == NULL) {
    perror("生成哈希失败");
    free(username);
    free(password);
    free(salt);
    exit(1);
}

4. 密码输入的小优化(可选)

你用getchar()读取密码会在终端明文显示,这不安全,建议用getpass()或者readpassphrase()来隐藏输入:

cout << "Enter your password: ";
char* passInput = getpass("");
password = strdup(passInput); // 复制到动态内存,避免静态内存被后续调用覆盖

完整修正后的代码

#include<stdio.h>
#include<cstdlib>
#include<iostream>
#include<fstream>
#include<ctime>
#include<crypt.h>
#include<unistd.h>
#include<cstring>
using namespace std;

/*====== READ STRING DYNAMICALLY ======*/
char* readFromTerminal() {
    int length = 0;
    char c;
    char *input = (char *) malloc(sizeof(char));
    if (input == NULL) {
        printf("Could not allocate memory!");
        exit(1);
    }
    while ((c = getchar()) != '\n' && c != EOF) {
        char* temp = (char*)realloc(input, (length + 2) * sizeof(char));
        if (temp == NULL) {
            printf("Could not allocate memory!");
            free(input);
            exit(1);
        }
        input = temp;
        input[length++] = c;
    }
    input[length] = '\0';
    return input;
}

/*====== GENERATE PSEUDO RANDOM SALT VALUE ======*/
char* generateSalt() {
    const char alphanum[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz./";
    int saltLen = 16; // SHA-512 salt最多16个字符
    char* salt = (char*)malloc(3 + saltLen + 2); // $6$ + salt + $ + \0
    if (salt == NULL) {
        printf("Could not allocate memory!");
        exit(1);
    }
    strcpy(salt, "$6$"); // 使用SHA-512哈希算法
    srand(time(NULL));
    for (int i = 0; i < saltLen; i++) {
        salt[3 + i] = alphanum[rand() % (sizeof(alphanum)-1)];
    }
    salt[3 + saltLen] = '$';
    salt[3 + saltLen + 1] = '\0';
    return salt;
}

/*====== MAIN ======*/
int main(int argc, char** argv) {
    char *username, *password, *salt, *hash;
    ofstream myshadow("myshadow.txt", ios::out);

    cout << "Enter your username: ";
    username = readFromTerminal();

    cout << "Enter your password: ";
    char* passInput = getpass("");
    password = strdup(passInput);

    salt = generateSalt();
    hash = crypt(password, salt);
    if (hash == NULL) {
        perror("Failed to generate hash");
        free(username);
        free(password);
        free(salt);
        exit(1);
    }

    myshadow << username << ":" << hash << endl;
    cout << "User added to myshadow.txt successfully!" << endl;

    // 释放动态分配的内存
    free(username);
    free(password);
    free(salt);
    myshadow.close();
    return 0;
}

编译提示

编译的时候记得链接crypt库,比如用g++:

g++ yourfile.cpp -o yourfile -lcrypt

这样修改后,同一个密码和salt会生成稳定的哈希值,再也不会出现无返回的情况啦。

内容的提问来源于stack exchange,提问作者Giannis Savvidis

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 07:47:26