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

