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

Chrome加密密钥解密失败:CryptUnprotectData返回错误13求助

解密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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 15:38:09