如何在Python中解密C#的AES加密数据?

How to decrypt a AES encrypted data of C# in Python?

我正在尝试用 C# 加密文本,然后尝试在 Python 中解密数据,但我无法在 python 中解密 C# 加密数据。我想也许我无法获得与我在 C# 中使用的相同的 IV。 我不知道我哪里错了。

class AesEncryption
{
    public static void Main()
    {
        var original = "Here is some data to encrypt!";



        using (var myAes = Aes.Create())
        {
            var key = "My private key";
            myAes.Key = Encoding.ASCII.GetBytes(key);
            myAes.Mode = CipherMode.CBC;
            myAes.IV = new byte[16];

            // Encrypt the string to an array of bytes.
            var encrypted = EncryptStringToBytes_Aes(original, myAes.Key, myAes.IV);

            Console.WriteLine("Encrypted:   {0}", encrypted);

            // Decrypt the bytes to a string.
            var roundtrip =
                DecryptStringFromBytes_Aes(System.Convert.FromBase64String(encrypted), myAes.Key, myAes.IV);

            //Display the original data and the decrypted data.
            Console.WriteLine("Original:   {0}", original);
            Console.WriteLine("Round Trip: {0}", roundtrip);
        }
    }

    private static string EncryptStringToBytes_Aes(string plainText, byte[] key, byte[] iv)
    {
        // Check arguments.
        if (plainText == null || plainText.Length <= 0)
            throw new ArgumentNullException(nameof(plainText));
        if (key == null || key.Length <= 0)
            throw new ArgumentNullException(nameof(key));
        if (iv == null || iv.Length <= 0)
            throw new ArgumentNullException(nameof(iv));

        // Create an Aes object
        // with the specified key and IV.
        using var aesAlg = Aes.Create();
        aesAlg.Key = key;
        aesAlg.IV = iv;

        // Create an encryptor to perform the stream transform.
        var encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);

        // Create the streams used for encryption.
        using var msEncrypt = new MemoryStream();
        using var csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write);
        using (var swEncrypt = new StreamWriter(csEncrypt))
        {
            //Write all data to the stream.
            swEncrypt.Write(plainText);
        }

        var encrypted = msEncrypt.ToArray();

        // Return the encrypted bytes from the memory stream.
        return Convert.ToBase64String(encrypted);
    }

    private static string DecryptStringFromBytes_Aes(byte[] cipherText, byte[] key, byte[] iv)
    {
        // Check arguments.
        if (cipherText == null || cipherText.Length <= 0)
            throw new ArgumentNullException(nameof(cipherText));
        if (key == null || key.Length <= 0)
            throw new ArgumentNullException(nameof(key));
        if (iv == null || iv.Length <= 0)
            throw new ArgumentNullException(nameof(iv));

        // Declare the string used to hold
        // the decrypted text.
        string plaintext;

        // Create an Aes object
        // with the specified key and IV.
        using (var aesAlg = Aes.Create())
        {
            aesAlg.Key = key;
            aesAlg.IV = iv;

            // Create a decryptor to perform the stream transform.
            var decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);

            // Create the streams used for decryption.
            using (var msDecrypt = new MemoryStream(cipherText))
            {
                using (var csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
                {
                    using (var srDecrypt = new StreamReader(csDecrypt))
                    {
                        // Read the decrypted bytes from the decrypting stream
                        // and place them in a string.
                        plaintext = srDecrypt.ReadToEnd();
                    }
                }
            }
        }

        return plaintext;
    }
}

我正在使用IV iv = as new byte[16]; 在上面的代码中,我正在检查在加密和解密过程中生成的加密文本是什么,并试图在我的 python 加密中匹配它。

import base64
import binascii
import hashlib

from Crypto.Cipher import AES


def r_pad(payload, block_size=16):
    length = block_size - (len(payload) % block_size)
    return payload + chr(length) * length


key = "My private key"
body = "Here is some data to encrypt!"
iv = binascii.unhexlify(16 * "00")
length = len(body)
encoded_key = hashlib.sha256(key.encode()).digest()
data_from_encryption = r_pad(body).encode('utf-8')

encrypted_data = AES.new(encoded_key, AES.MODE_CBC, iv).encrypt(data_from_encryption)
encrypted_data_to_base64_str = base64.b64encode(encrypted_data).decode('utf-8')
print("Encrypted data: ", encrypted_data_to_base64_str)
bytes_to_decrypt = base64.decodebytes(encrypted_data_to_base64_str.encode())
decrypted_data = AES.new(encoded_key, AES.MODE_CBC, iv).decrypt(bytes_to_decrypt)[:length]
decode_str = decrypted_data.decode('utf-8')
print(decode_str)

我尝试使用不同的 IV 值 iv = binascii.unhexlify(16 * "00")

但无法在两种代码中获得相同的加密文本。 我也知道 r_pad 函数在 python 中做什么,但如果我不使用它 Python 会引发异常,关于我的数据未根据 16 位

进行填充

任何人都可以帮助我并告诉我哪里错了吗?

在C#代码中,密钥是key的ASCII编码,但在Python代码中是key的SHA-256散列。

以便Python代码产生相同的密文,只需替换:

encoded_key = key.encode('ascii')

注意以下问题:

  • 静态 IV 是不安全的。通常,每次加密都会生成一个随机 IV,并与密文一起传递(通常是串联的)。
  • 如果要从密码派生密钥,则应使用可靠的密钥派生函数,例如 Argon2 或 PBKDF2,而不是摘要。
  • PyCryptodome 在专用模块中支持填充:Crypto.Util.Padding