我有一个c#客户端,用于解密AES加密消息。我尝试在python客户端中实现c#逻辑,但是结果不一样,并且充满了问号和模糊字符。
我正在将python 3.5与运行薄荷x64的pycrypto一起使用。 C#客户端的代码和下面提供的代码的python版本:
c#代码:
string EncryptionKey = "MAKV2SPBNI99212";
byte[] cipherBytes = Convert.FromBase64String(cipherText); //Get the encrypted message's bytes
using (Aes encryptor = Aes.Create()) //Create a new AES object
{
//Decrypt the text
Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes(EncryptionKey, new byte[] { 0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76 });
encryptor.Key = pdb.GetBytes(32);
encryptor.IV = pdb.GetBytes(16);
using (MemoryStream ms = new MemoryStream())
{
using (CryptoStream cs = new CryptoStream(ms, encryptor.CreateDecryptor(), CryptoStreamMode.Write))
{
cs.Write(cipherBytes, 0, cipherBytes.Length);
cs.Close();
}
plainText = Encoding.Unicode.GetString(ms.ToArray());
}
我的python版本:
def decode_base64(data, altchars=b'+/'):
"""Decode base64, padding being optional.
:param data: Base64 data as an ASCII byte string
:returns: The decoded byte string.
"""
data = re.sub(rb'[^a-zA-Z0-9%s]+' % altchars, b'', data) # normalize
missing_padding = len(data) % 4
if missing_padding:
data += b'='* (4 - missing_padding)
return base64.b64decode(data, altchars)
def decode_message(data, key):
enc_txt = decode_base64(bytes(data, 'utf-16'))
salt_t = ["0x49", "0x76", "0x61", "0x6e", "0x20", "0x4d", "0x65", "0x64", "0x76", "0x65", "0x64", "0x65", "0x76"]
salt = bytes([int(x, 0) for x in salt_t])
key_bytes = KDF.PBKDF2(key, salt, 32, 1000)
# iv = enc_txt[:16] // using this line instead of the below line, has no effects on final result
iv = KDF.PBKDF2(key, salt, 16, 1000)
cipher = AES.new(key_bytes, AES.MODE_CBC, iv)
return cipher.decrypt(enc_txt).decode('utf-16')
c#客户端运行正常,但是我的python客户端生成的字符模糊而不是实际的预期消息。
我遇到了这个post 我认为我也有类似的问题,但我无法理解提供的答案。 任何答案将不胜感激。预先感谢。
更新:C#服务器端加密: 这也是C#服务器端加密代码,我认为这个问题基于链接的问题涵盖了方案的多个方面,并且可以为面临相同问题(编码,加密,填充...)的任何人提供参考>
string EncryptionKey = "MAKV2SPBNI99212"; //Declare the encryption key (it's not the best thing to do)
byte[] clearBytes = Encoding.Unicode.GetBytes(clearText); //Get the bytes of the message
using (Aes encryptor = Aes.Create()) //Create a new aes object
{
Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes(EncryptionKey, new byte[] { 0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76 });
encryptor.Key = pdb.GetBytes(32); //Set the encryption key
encryptor.IV = pdb.GetBytes(16); //Set the encryption IV
using (MemoryStream ms = new MemoryStream()) //Create a new memory stream
{
using (CryptoStream cs = new CryptoStream(ms, encryptor.CreateEncryptor(), CryptoStreamMode.Write)) //Create a new crypto stream
{
cs.Write(clearBytes, 0, clearBytes.Length); //Write the command to the crypto stream
cs.Close(); //Close the crypto stream
}
cipherText = System.Convert.ToBase64String(ms.ToArray()); //Convert the encrypted bytes to a Base64 string
答案 0 :(得分:0)
在Python代码中错误地确定了IV,因此应按以下方式更改代码:
keyiv = KDF.PBKDF2(key, salt, 48, 1000)
key = keyiv[:32]
iv = keyiv[32:48]
此外,C#代码中使用PKCS7填充,因此在解密过程中Python代码中需要进行非填充。一种可能性是Crypto.Util.Padding
:
import Crypto.Util.Padding as padding
...
decryptedPadded = cipher.decrypt(enc_txt)
decrypted = padding.unpad(decryptedPadded, 16) # Pkcs7 unpadding
return decrypted.decode('utf-16') # UTF-16LE decoding including BOM-removal
使用C#代码UTF-16LE(Encoding.Unicode
)对编码的数据进行加密。数据之前有2字节BOM(0xFFFE
)。在UTF-16LE解码期间,该BOM会自动删除。
Python代码中的方法decode_base64
似乎已从here中采用。此方法应重建丢失的Base64填充。我不太确定为什么在这里需要这样做。同样,调用该方法时密文的UTF-16编码对我来说毫无意义。实际上,对密文进行简单的Base64解码就足够了:
import base64
...
enc_txt = base64.b64decode(data)
但是也许我错过了某些方面。
答案 1 :(得分:0)
@Topaco 感谢您的解释和回答。
在此处粘贴完整代码,供遇到相同问题的人使用。
import base64
import Crypto.Util.Padding as padding
from Crypto.Cipher import AES
from Crypto.Protocol import KDF
from pbkdf2 import PBKDF2
def decrypt(data, key):
enc_txt = base64.b64decode(data)
salt_t = ["0x49", "0x76", "0x61", "0x6e", "0x20", "0x4d", "0x65", "0x64", "0x76", "0x65", "0x64", "0x65", "0x76"]
salt = bytes([int(x, 0) for x in salt_t])
key_bytes = KDF.PBKDF2(key, salt, 32, 1000)
iv = KDF.PBKDF2(key, salt, 48, 1000)[32:48]
cipher = AES.new(key_bytes, AES.MODE_CBC, iv)
decryptedPadded = cipher.decrypt(enc_txt)
decrypted = padding.unpad(decryptedPadded, 16) # Pkcs7 unpadding
return decrypted.decode('utf-16') # UTF-16LE decoding including BOM-removal