C++ Argon2id哈希生成异常:无法将HEX格式结果转换为标准Argon2id哈希字符串
C++ Argon2id哈希生成异常:无法将HEX格式结果转换为标准Argon2id哈希字符串
看起来你现在卡在了“把生成的Argon2id HEX哈希转换成标准格式字符串”这一步对吧?我帮你拆解下问题核心,再给你修正后的代码方案。
首先得明确:标准Argon2id哈希字符串是用$分隔的结构化组合,它的格式是这样的:
$argon2id$v=19$m=16,t=2,p=1$[URL安全Base64编码的salt]$[URL安全Base64编码的哈希值]
你现在拿到的是HEX格式的哈希,这只是其中的一部分,还需要把参数、salt的Base64编码版本和它拼在一起才行。而且这里有几个容易踩坑的点:
- 标准格式里用的是URL安全的Base64编码(替换
+为-、/为_,且无填充字符=),不是普通Base64,也不是HEX - Salt不能直接用明文,必须转成Base64编码
- 参数顺序必须是
m=内存成本,t=迭代次数,p=并行度,不能乱序 - 版本号
v=19对应的是Argon2的ARGON2_VERSION_13版本,这是当前的稳定标准
接下来看你的代码问题:你应该是只生成了哈希的HEX值,没有完成后续的编码和拼接步骤。下面是修正后的完整代码,包含了从生成哈希到组装成标准格式的全流程:
#include <argon2.h> #include <string.h> #include <vector> #include <algorithm> #include <string> // 辅助函数:实现URL安全的Base64编码(无填充字符) std::string base64_url_encode(const uint8_t* data, size_t len) { const std::string base64_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz" "0123456789-_"; std::string result; int i = 0; int j = 0; uint8_t char_array_3[3]; uint8_t char_array_4[4]; while (len--) { char_array_3[i++] = *(data++); if (i == 3) { char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4); char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6); char_array_4[3] = char_array_3[2] & 0x3f; for(i = 0; (i <4) ; i++) result += base64_chars[char_array_4[i]]; i = 0; } } if (i) { for(j = i; j < 3; j++) char_array_3[j] = '\0'; char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4); char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6); char_array_4[3] = char_array_3[2] & 0x3f; for (j = 0; (j < i + 1); j++) result += base64_chars[char_array_4[j]]; } // 确保移除所有填充字符(这里我们本身就没生成,但保险起见) result.erase(std::remove(result.begin(), result.end(), '='), result.end()); return result; } std::string DBManager::Argon2PasswordHash(const char* password) { // 你指定的参数配置 const uint32_t t_cost = 2; // 迭代次数 const uint32_t m_cost = 16; // 内存成本(单位:KB) const uint32_t parallelism = 1; // 并行度 const uint32_t hash_len = 64; // 哈希长度 const uint32_t argon2_version = ARGON2_VERSION_13; // 对应v=19 // Salt配置 uint8_t salt[] = "MYSALTISCOOL"; const uint32_t salt_len = strlen(reinterpret_cast<char*>(salt)); // 分配内存存储原始哈希字节数组 std::vector<uint8_t> hash_result(hash_len); // 调用Argon2id生成原始哈希(直接生成字节数组,避免先转HEX的额外步骤) int ret = argon2id_hash_raw( t_cost, m_cost, parallelism, password, strlen(password), salt, salt_len, hash_result.data(), hash_len, nullptr, 0, argon2_version ); // 处理哈希生成错误 if (ret != ARGON2_OK) { // 这里可以根据需要返回错误标识或抛出异常 return ""; } // 对salt和哈希结果进行URL安全的Base64编码 std::string salt_b64 = base64_url_encode(salt, salt_len); std::string hash_b64 = base64_url_encode(hash_result.data(), hash_len); // 按照标准格式拼接所有部分 std::string final_hash = "$argon2id$v=" + std::to_string(argon2_version) + "$m=" + std::to_string(m_cost) + ",t=" + std::to_string(t_cost) + ",p=" + std::to_string(parallelism) + "$" + salt_b64 + "$" + hash_b64; return final_hash; }
几个关键的修正点说明:
- 改用
argon2id_hash_raw直接生成哈希字节数组,跳过了转HEX的步骤,既高效又方便后续转Base64 - 实现了符合Argon2标准的URL安全Base64编码,确保生成的字符串和目标格式一致
- 严格按照标准格式拼接参数、salt编码、哈希编码,参数顺序完全匹配要求
- 明确指定了Argon2版本为
ARGON2_VERSION_13,对应格式里的v=19
你可以测试下这段代码,只要你的密码和参数完全匹配,生成的哈希字符串应该就和你给出的目标示例一致了。
备注:内容来源于stack exchange,提问作者André Santos
相关产品推荐
相关产品推荐

