Python 中使用 C# 加密的错误解密

问题描述 投票:0回答:1

在C#中加密一个字符串,在Python中解密失败,显然问题出在IV

代码输入pt 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]

我是用C#加密的原始字符串,用Python解密,但不知道我做错了什么

我遵循了这些建议,但它们不起作用 调整 C# 的实现以匹配 Python 的实现时需要考虑的关键方面是:

加密密钥转换:确保 C# 中的加密密钥处理方式与 Python 中的处理方式相同。这包括如何从 Base64 转换为字节。

密钥和 IV 推导:在 Python 中,我们使用 PBKDF2HMAC 和 SHA256 来推导密钥和 IV。确保 C# 使用相同的算法和过程来生成密钥。

encryption cryptography pycrypto
1个回答
0
投票

你好 我花了一周时间寻找解决方案,希望你不必受苦这么久:)

解决方案:

在 C# 中,我从同一个 Rfc2898DeriveBytes 对象获取密钥和 IV。这是一种不寻常的做法,因为 IV 通常是随机生成的,并与密文一起传输,或者保持不变并为加密和解密过程的双方所知。在您的情况下,您从相同的源(密钥和盐)生成 IV,但在生成密钥之后,这意味着 IV 将取决于密钥。

在 Python 中,我正在做类似的事情:我使用 PBKDF2 从同一源生成密钥和 IV。但是,由于我不使用相同的 PBKDF2 对象(如在 C# 中使用 Rfc2898DeriveBytes 所做的那样),因此 Python 中生成的 IV 很可能与 C# 中生成的 IV 不匹配。

这是在 C# 中加密然后能够在 python 中解密的正确方法

澄清一下,我的加密密钥位于 Visual Studio 开发机密主干中 您可以在此变量中替换您的密钥:mybase64Key ='myEncryptionKey'

使用这种方法来解决问题:随机生成IV并发送它 更常见和安全的做法是为每个密码随机生成 IV,然后将其与密文一起传输。这意味着 IV 不需要从密钥导出。

C# 代码更正加密

using System.Security.Cryptography;
using System;
using System.IO;
using System.Text;
using Chatne.WebApp.Server.Services.Contracts;
using Chatne.WebApp.Server.Models;

namespace Chatne.WebApp.Server.Services
{
    public class HelpersService : IHelpersService
    {
        private static readonly byte[] Salt = Encoding.ASCII.GetBytes("MiSalt");
        private const int Iterations = 1000; // Puede ser ajustado

        private readonly IConfiguration _configuration;
        private readonly byte[] _encryptionKey;
        private readonly byte[] _salt;
        private readonly int _iterations;

        public HelpersService(IConfiguration configuration)
        {
            _configuration = configuration;
            var mybase64Key = _configuration["Encryption:Key"]
                .Replace('_', '/')
                .Replace('-', '+');

            _encryptionKey = Convert.FromBase64String(mybase64Key);
            _salt = Encoding.UTF8.GetBytes("MiSalt");
            _iterations = 1000; // Número de iteraciones para PBKDF2
        }


        public string Encrypt(string plainText, string salt = null)
        {
            if (string.IsNullOrEmpty(plainText))
                return null;

            byte[] saltBytes = _salt;
            if (!string.IsNullOrEmpty(salt))
            {
                saltBytes = Encoding.UTF8.GetBytes(salt);
            }

            using (var rfc2898DeriveBytes = new Rfc2898DeriveBytes(_encryptionKey, saltBytes, _iterations))
            {
                byte[] key = rfc2898DeriveBytes.GetBytes(32); // 256 bits para la clave
                byte[] iv = rfc2898DeriveBytes.GetBytes(16);  // 128 bits para el IV

                using (var aes = Aes.Create())
                {
                    aes.KeySize = 256;
                    aes.BlockSize = 128;
                    aes.Mode = CipherMode.CBC;
                    aes.Padding = PaddingMode.PKCS7;
                    aes.Key = key;
                    aes.GenerateIV(); // Generar un IV aleatorio
                    iv = aes.IV;


                    using (var encryptor = aes.CreateEncryptor(aes.Key, aes.IV))
                    using (var ms = new MemoryStream())
                    using (var cryptoStream = new CryptoStream(ms, encryptor, CryptoStreamMode.Write))
                    {
                        byte[] plainBytes = Encoding.UTF8.GetBytes(plainText);
                        cryptoStream.Write(plainBytes, 0, plainBytes.Length);
                        cryptoStream.FlushFinalBlock();

                        byte[] encrypted = ms.ToArray();
                        // El IV debe ser enviado junto con el texto cifrado
                        byte[] encryptedAndIv = new byte[iv.Length + encrypted.Length];
                        Buffer.BlockCopy(iv, 0, encryptedAndIv, 0, iv.Length);
                        Buffer.BlockCopy(encrypted, 0, encryptedAndIv, iv.Length, encrypted.Length);


                        return Convert.ToBase64String(encryptedAndIv);
                    }
                }
            }
        }
}

使用 Python 进行解密的代码更正

from Crypto.Cipher import AES
from Crypto.Protocol.KDF import PBKDF2
import base64

class Decryptor:
    def __init__(self, encryption_key):
        self.encryption_key = base64.b64decode(encryption_key)
        self.salt = b'AgenteSalt'  # El salt debe ser el mismo que en C#
        self.iterations = 1000  # El número de iteraciones debe ser el mismo que en C#

    def decrypt(self, cipher_text):
        encrypted_bytes = base64.b64decode(cipher_text)
        iv = encrypted_bytes[:16]  # Asume que los primeros 16 bytes son el IV
        encrypted_bytes = encrypted_bytes[16:]  # Resto es el texto cifrado

        key = PBKDF2(self.encryption_key, self.salt, dkLen=32, count=self.iterations)
        cipher = AES.new(key, AES.MODE_CBC, iv)
        decrypted = cipher.decrypt(encrypted_bytes)

        # Remover el padding PKCS7
        pad_size = decrypted[-1]
        if isinstance(pad_size, str):  # Python 2.x compatibilidad
            pad_size = ord(pad_size)
        decrypted = decrypted[:-pad_size]

        return decrypted.decode('utf-8')
© www.soinside.com 2019 - 2024. All rights reserved.