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

C#加密字符串后Python解密失败(疑似IV推导错误)

C# AES加密字符串的Python解密故障排查与修复

我用以下C#代码实现字符串AES加密,但对应的Python解密代码无法正常工作,疑似IV推导逻辑错误。需要调整Python代码,使其能正确解密C#加密后的内容。


C# 加密代码

public string Encrypt(string plainText)
{
    // Transformar la clave de encriptación de Base64 a bytes
    var base64Key = "MiEncryptKey=".Replace('_', '/').Replace('-', '+');
    var keyBytes = Convert.FromBase64String(base64Key);

    // Derivar la clave y el IV usando Rfc2898DeriveBytes con SHA256
    var salt = Encoding.UTF8.GetBytes("AgenteSalt");
    var pdb = new Rfc2898DeriveBytes(keyBytes, salt, 1000);
    var key = pdb.GetBytes(32);
    var iv = pdb.GetBytes(16);

    // Configurar el cifrador AES en modo CBC con PKCS7 padding
    using (var aes = new RijndaelManaged())
    {
        aes.KeySize = 256;
        aes.BlockSize = 128;
        aes.Padding = PaddingMode.PKCS7;
        aes.Mode = CipherMode.CBC;
        aes.Key = key;
        aes.IV = iv;

        // Encriptar el texto
        using (var ms = new MemoryStream())
        {
            using (var cs = new CryptoStream(ms, aes.CreateEncryptor(), CryptoStreamMode.Write))
            {
                var bytes = Encoding.UTF8.GetBytes(plainText);
                cs.Write(bytes, 0, bytes.Length);
                cs.Close();
            }
            var encrypted = ms.ToArray();

            // Codificar el resultado en Base64
            return Convert.ToBase64String(encrypted);
        }
    }
}

原Python解密代码(无法正常工作)

from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
import base64

class Decryptor:
    def __init__(self, base64_key, salt=b"MiSalt"):
        self.base64_key = base64_key.replace('_', '/').replace('-', '+')
        self.encryption_key = base64.b64decode(self.base64_key)
        self.salt = salt
        self.iterations = 1000

    def _get_cipher(self):
        # Usando SHA1 aquí para coincidir con el algoritmo de hash de C#
        kdf = PBKDF2HMAC(
            algorithm=hashes.SHA1(),
            length=32,
            salt=self.salt,
            iterations=self.iterations,
            backend=default_backend()
        )
        key = kdf.derive(self.encryption_key)
        iv = key[:16]
        return Cipher(algorithms.AES(key), modes.CBC(iv), backend=default_backend())

    def decrypt(self, cipher_text):
        cipher = self._get_cipher()
        decryptor = cipher.decryptor()
        ct = base64.b64decode(cipher_text)
        decrypted = decryptor.update(ct) + decryptor.finalize()
        return self._unpad(decrypted)

    def _unpad(self, s):
        pad_size = s[-1]
        if pad_size > 16:
            raise ValueError("Invalid padding")
        return s[:-pad_size]

核心问题分析

  • Salt不匹配:C#代码中使用的salt是"AgenteSalt"的UTF-8字节,而Python代码错误使用了b"MiSalt",直接导致密钥和IV的推导结果完全不同。
  • IV推导逻辑错误:C#中Rfc2898DeriveBytes是连续生成字节流——先取32字节作为密钥,再从同一流的下一个位置取16字节作为IV;但Python代码错误地将密钥的前16字节当作IV,和C#逻辑完全不符。
  • 注:C#的Rfc2898DeriveBytes默认使用SHA1哈希算法,Python代码中这部分是正确的。

修正后的Python解密代码

from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
import base64

class Decryptor:
    def __init__(self, base64_key):
        self.base64_key = base64_key.replace('_', '/').replace('-', '+')
        self.encryption_key = base64.b64decode(self.base64_key)
        # 匹配C#中的salt:"AgenteSalt"的UTF-8字节
        self.salt = b"AgenteSalt"
        self.iterations = 1000

    def _get_cipher(self):
        # 生成足够长度的派生字节:32字节key + 16字节iv = 48字节
        kdf = PBKDF2HMAC(
            algorithm=hashes.SHA1(),
            length=48,
            salt=self.salt,
            iterations=self.iterations,
            backend=default_backend()
        )
        derived_bytes = kdf.derive(self.encryption_key)
        key = derived_bytes[:32]  # 前32字节作为密钥,和C#一致
        iv = derived_bytes[32:]   # 后16字节作为IV,和C#逻辑匹配
        return Cipher(algorithms.AES(key), modes.CBC(iv), backend=default_backend())

    def decrypt(self, cipher_text):
        cipher = self._get_cipher()
        decryptor = cipher.decryptor()
        ct = base64.b64decode(cipher_text)
        decrypted = decryptor.update(ct) + decryptor.finalize()
        return self._unpad(decrypted).decode('utf-8')

    def _unpad(self, s):
        # PKCS7解包逻辑:最后一个字节的值就是填充长度
        pad_size = s[-1]
        if pad_size < 1 or pad_size > 16:
            raise ValueError("Invalid padding")
        return s[:-pad_size]

修正说明

  1. 同步salt值为b"AgenteSalt",和C#保持一致。
  2. 修改KDF的length参数为48,一次性生成足够的派生字节,再拆分出32字节密钥和16字节IV,完全匹配C#的GetBytes(32)+GetBytes(16)逻辑。
  3. 解密后增加decode('utf-8'),将字节流转换为字符串。
  4. 优化解包逻辑的校验条件,确保符合PKCS7规范。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 16:35:01