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

如何在Rust中使用指定字节密钥实现AES-GCM解密?

解决Python AES-GCM解密迁移到Rust的问题

问题核心梳理

你在迁移过程中遇到的三个问题,本质都是数据处理流程不匹配和Rust API使用误区,逐个拆解解决:


1. 密钥长度问题:从267字节到32字节的正确处理

问题原因

你拿到的267字节是未处理的encrypted_key(base64解码后的数据),Python中会先去掉前5字节的DPAPI前缀,再通过CryptUnprotectData解密得到标准AES-256所需的32字节密钥。

Rust实现方案

用dpapi crate直接实现Windows DPAPI解密,替代Python的win32crypt.CryptUnprotectData:

use base64::engine::{general_purpose, Engine as _};
use dpapi::UnprotectData;
use serde_json::Value;
use std::fs;

fn get_master_key(path: &str) -> Result<Vec<u8>, Box<dyn std::error::Error>> {
    // 读取并解析Local State文件
    let local_state = fs::read_to_string(path)?;
    let json: Value = serde_json::from_str(&local_state)?;
    
    // 提取base64编码的加密密钥并解码
    let encrypted_key_b64 = json["os_crypt"]["encrypted_key"].as_str().ok_or("无效的encrypted_key")?;
    let mut encrypted_key = general_purpose::STANDARD.decode(encrypted_key_b64)?;
    
    // 移除前5字节的DPAPI前缀
    encrypted_key.drain(0..5);
    
    // 调用DPAPI解密得到32字节的AES密钥
    let protected_data = encrypted_key.as_slice().unprotect_data(None, None)?;
    Ok(protected_data.0)
}

将处理后的密钥转为Rust AES-GCM所需的格式:

use aes_gcm::{Aes256Gcm, Key};

// master_key是get_master_key返回的Vec<u8>,长度固定32
let key = Key::<Aes256Gcm>::from_slice(&master_key);
let cipher = Aes256Gcm::new(key);

2. aead::Error排查:输入数据处理错误是核心

最关键错误:未做base64解码

Python代码会先对匹配到的字符串(冒号后部分)做base64解码,再提取IV和密文;但你的Rust代码直接用原始字符串的字节处理,完全不符合数据格式要求,这是解密失败的主要原因。

修正后的解密函数

use aes_gcm::{Aes256Gcm, Key, Nonce, aead::{Aead, KeyInit}};
use base64::engine::{general_purpose, Engine as _};

fn decrypt_encrypted_strings(input_str: &str, master_key: &[u8]) -> Result<String, Box<dyn std::error::Error>> {
    // 分割出冒号后的base64编码部分
    let (_, b64_part) = input_str.split_once(":").ok_or("输入格式错误")?;
    // base64解码得到原始加密字节数组
    let buff = general_purpose::STANDARD.decode(b64_part)?;
    
    // 提取12字节的IV(GCM标准nonce长度)
    let nonce = Nonce::from_slice(&buff[3..15]);
    // 提取密文+Tag(GCM中Tag默认16字节,附在密文后)
    let ciphertext_with_tag = &buff[15..];
    
    // 创建AES-GCM实例并解密(自动验证Tag)
    let key = Key::<Aes256Gcm>::from_slice(master_key);
    let cipher = Aes256Gcm::new(key);
    let plaintext = cipher.decrypt(nonce, ciphertext_with_tag)?;
    
    // 将明文转为UTF-8字符串
    let plaintext_str = String::from_utf8(plaintext)?;
    Ok(plaintext_str)
}

其他可能的错误点

  • 如果仍出现aead::Error,优先检查:
    1. Rust解码后的buff与Python中base64.b64decode结果是否完全一致
    2. 处理后的master key是否和Python输出的密钥完全相同
    3. 输入字符串是否完整包含dQw4w9WgXcQ:前缀和后续的base64内容

3. 调用代码修正

确保传入正确的输入数据和处理后的密钥:

// 先获取处理好的master key
let master_key = get_master_key("path/to/Local State").unwrap();
let mut decrypted_strings = Vec::new();

for line in s.lines() {
    if let Some(mat) = re.captures(line) {
        let input_str = mat.get(0).unwrap().as_str();
        match decrypt_encrypted_strings(input_str, &master_key) {
            Ok(text) => {
                if !decrypted_strings.contains(&text) {
                    decrypted_strings.push(text);
                }
            }
            Err(e) => eprintln!("解密失败: {}", e),
        }
    }
}

Cargo.toml依赖配置

添加所需的crate:

[dependencies]
aes-gcm = "0.10.1"
base64 = "0.21.5"
dpapi = "0.4.0"
serde_json = "1.0.108"
regex = "1.10.2"

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 19:15:23