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

如何生成与crypt函数一致的哈希密码?手动实现差异排查

Why does my manual SHA512 hash differ from crypt()'s $6$ output?

Great question! The core issue here is that your code is doing a simple concatenation of salt + password followed by a single SHA512 hash, but the $6$ prefix in your crypt() call specifies the SHA-512 Crypt algorithm—a much more complex, iterative hashing scheme designed specifically for password storage, not a basic SHA512 hash.

Let’s break down why the results don’t match:

1. SHA-512 Crypt ≠ Basic SHA512

SHA-512 Crypt isn’t just a one-and-done hash. It’s a password hashing algorithm that:

  • Uses thousands of iterative rounds (default is 5000, configurable) to slow down brute-force attacks.
  • Mixes the password, salt, and intermediate hash results in a specific, non-trivial sequence (e.g., starting with SHA512(password + salt + password), then repeatedly combining that result with the original password and salt).
  • Uses a custom Base64 encoding scheme (using ./0-9A-Za-z instead of the standard +/0-9A-Za-z character set) to encode the final hash.

Your code skips all of this complexity—it just hashes the salt and password once with standard SHA512, then uses standard Base64. That’s why the outputs look nothing alike.

2. How to Generate a crypt()-Compatible Hash

You have two reliable options here:

Option 1: Stick with the system crypt() function (simplest & most secure)

Your code already calls crypt() correctly—this is the best approach because it leverages the system’s optimized, secure implementation of SHA-512 Crypt. There’s no need to reinvent the wheel here.

If you absolutely need to use OpenSSL APIs to replicate crypt()’s behavior, you’ll have to strictly follow the SHA-512 Crypt specification. This involves:

  • Handling the iterative hash mixing steps (dozens of rounds combining password, salt, and intermediate hashes).
  • Using the custom Base64 encoding for the final output.

This is error-prone and unnecessary when crypt() is available, but if you’re curious, the algorithm details are documented in the official SHA-Crypt specification.

Example of the Correct Approach

Your existing crypt() call is already correct—here’s a cleaned-up version of your code that leans into that:

#include <stdio.h>
#include <string.h>
#include <crypt.h>
#include <openssl/sha.h>
#include <string>

// Assume base64_encode is defined elsewhere
std::string base64_encode(unsigned char const* bytes_to_encode, unsigned int in_len);

int main() {
    const char *password = "123456";
    const char *salt = "$6$123456"; // Explicitly specify SHA-512 Crypt algorithm

    // Your manual (incorrect) approach
    unsigned char hashedPasswd[SHA512_DIGEST_LENGTH];
    SHA512_CTX context;
    if (!SHA512_Init(&context)) return -1;
    if (!SHA512_Update(&context, (unsigned char *)"123456", strlen("123456"))) return -1;
    if (!SHA512_Update(&context, (unsigned char *)password, strlen(password))) return -1;
    if (!SHA512_Final(hashedPasswd, &context)) return -1;
    std::string base64Data = base64_encode(hashedPasswd, sizeof(hashedPasswd));
    printf("my result: %s\n", base64Data.c_str());

    // Correct approach using crypt()
    char *hashedPassword = crypt(password, salt);
    printf("crypt result: %s\n", hashedPassword);

    return 0;
}

Key Takeaway

Never implement password hashing algorithms from scratch—use battle-tested functions like crypt() or modern alternatives like Argon2 (via OpenSSL’s EVP APIs) to ensure your password hashes are secure and compatible with standard tools.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 08:34:49