Chrome加密密钥解密失败:CryptUnprotectData返回错误13求助
我正在做一个解密Chrome浏览器保存密码的项目,流程是读取Login Data文件里的密码,再用Local State文件中的encrypted_key解密。现在卡在解密encrypted_key这一步:能读取到encrypted_key,但用CryptoUnprotectData解密时返回False,错误码是13。
已知encrypted_key是经CryptoProtectData保护的Base64编码数据,我的代码如下:
#define DPAPI_PREFIX_LEN 5 static char encoding_table[] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/' }; static char* decoding_table = NULL; void build_decoding_table() { decoding_table = malloc(256); for (int i = 0; i < 64; i++) decoding_table[(unsigned char)encoding_table[i]] = i; } unsigned char* base64_decode(const char* data, SIZE_T input_length, SIZE_T* output_length) { if (decoding_table == NULL) build_decoding_table(); if (input_length % 4 != 0) return NULL; *output_length = input_length / 4 * 3; if (data[input_length - 1] == '=') (*output_length)--; if (data[input_length - 2] == '=') (*output_length)--; unsigned char* decoded_data = malloc(*output_length); if (decoded_data == NULL) return NULL; for (int i = 0, j = 0; i < input_length;) { uint32_t sextet_a = data[i] == '=' ? 0 & i++ : decoding_table[data[i++]]; uint32_t sextet_b = data[i] == '=' ? 0 & i++ : decoding_table[data[i++]]; uint32_t sextet_c = data[i] == '=' ? 0 & i++ : decoding_table[data[i++]]; uint32_t sextet_d = data[i] == '=' ? 0 & i++ : decoding_table[data[i++]]; uint32_t triple = (sextet_a << 3 * 6) + (sextet_b << 2 * 6) + (sextet_c << 1 * 6) + (sextet_d << 0 * 6); if (j < *output_length) decoded_data[j++] = (triple >> 2 * 8) & 0xFF; if (j < *output_length) decoded_data[j++] = (triple >> 1 * 8) & 0xFF; if (j < *output_length) decoded_data[j++] = (triple >> 0 * 8) & 0xFF; } return decoded_data; } int dpapi_decrypt(unsigned char* encText, unsigned long encTextSize, char* decText) { DATA_BLOB in; DATA_BLOB out; in.pbData = encText; in.cbData = encTextSize; if (CryptUnprotectData(&in, encText, NULL, NULL, NULL, 0, &out)) { for (int i = 0; i < out.cbData; i++) decText[i] = out.pbData[i]; decText[out.cbData] = '\0'; return 1; } int err = GetLastError(); printf("error: %d\n", err); return 0; } int key_decrypt(unsigned char* keyBase64, int keySize, unsigned char* decKey) { int key_decoded_len; unsigned char* key_decoded = base64_decode(keyBase64, keySize, &key_decoded_len); if (dpapi_decrypt(key_decoded + DPAPI_PREFIX_LEN, (key_decoded_len - DPAPI_PREFIX_LEN), (decKey))) { return 1; } return 0; }
问题出在dpapi_decrypt函数里的CryptUnprotectData调用,返回错误码13(ERROR_INVALID_DATA)。我参考过Python和C++的同类代码都能正常运行,但找不到可用的C语言示例,请问该怎么解决?
错误码13对应ERROR_INVALID_DATA,说明传入CryptUnprotectData的数据格式存在问题,以下是具体排查和修复方案:
修正
CryptUnprotectData的参数:
函数的第二个参数ppszDataDescr是输出参数,用于接收解密后的数据描述,你错误传入了输入加密数据encText,这会导致函数解析数据异常。将其改为NULL即可:if (CryptUnprotectData(&in, NULL, NULL, NULL, NULL, 0, &out))验证Base64解码结果:
确保从Local State的JSON中提取的encrypted_key是纯净的Base64字符串,没有多余的引号、转义符(如\)。可以在base64_decode后打印解码数据的前5个字节,确认是否为DPAPI(十六进制0x44 0x50 0x41 0x50 0x49)。如果解码结果不对,检查JSON解析逻辑是否正确提取了密钥字符串。确认DPAPI前缀截取正确:
Chrome的encrypted_key解码后确实以DPAPI5个字符开头,但如果提取的Base64字符串本身有误,解码后的前缀会不符合。可以在key_decrypt中添加打印:printf("Decoded prefix: %.5s\n", key_decoded);若输出不是
DPAPI,说明Base64字符串提取或解码出错。检查内存管理与运行权限:
base64_decode分配的内存未释放,建议在dpapi_decrypt调用后添加free(key_decoded)避免内存泄漏;CryptUnprotectData依赖当前用户的上下文,确保程序和Chrome在同一用户权限下运行,不要跨用户或用管理员权限解密普通用户的Chrome密钥。
内容的提问来源于stack exchange,提问作者EfM

