在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# 使用相同的算法和过程来生成密钥。
你好 我花了一周时间寻找解决方案,希望你不必受苦这么久:)
解决方案:
在 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')