在 python 中实现 C# 解密客户端时出现问题
problem implementing c# decryption client in python
我有一个可以解密 AES 加密消息的 c# 客户端。我试图在我的 python 客户端中实现 c# 逻辑,但结果不一样,并且充满了问号和模糊字符。
我正在使用 python 3.5 和 pycrypto 运行 mint x64。
下面提供了 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 客户端导致字符模糊,而不是实际预期的消息。
我运行变成这个
我想我有类似的问题,但我无法理解所提供的答案。
任何答案将不胜感激。提前致谢。
更新:C# 服务器端加密:
这也是 C# 服务器端加密代码,我认为这个问题涵盖了基于链接问题的场景的多个方面,并且可以作为面临相同问题(编码、加密、填充...)的任何人的参考。 15=]
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
Python代码中IV判断错误,应修改如下:
keyiv = KDF.PBKDF2(key, salt, 48, 1000)
key = keyiv[:32]
iv = keyiv[32:48]
此外,PKCS7 padding is used in the C# code, so that unpadding is necessary in the Python code during decryption. One possibility is 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
) encoded data are encrypted. The data are preceded by a 2 byte BOM(0xFFFE
)。UTF-16LE解码时会自动去掉这个BOM。
Python代码中的方法decode_base64
好像是从here沿袭过来的。此方法应重建丢失的 Base64 填充。我不太确定为什么这里有必要这样做。此外,调用方法时密文的 UTF-16 编码对我来说似乎毫无意义。其实一个简单的Base64解码密文应该就够了:
import base64
...
enc_txt = base64.b64decode(data)
但也许我错过了这里的某些方面。
@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
我有一个可以解密 AES 加密消息的 c# 客户端。我试图在我的 python 客户端中实现 c# 逻辑,但结果不一样,并且充满了问号和模糊字符。
我正在使用 python 3.5 和 pycrypto 运行 mint x64。 下面提供了 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 客户端导致字符模糊,而不是实际预期的消息。
我运行变成这个
更新:C# 服务器端加密: 这也是 C# 服务器端加密代码,我认为这个问题涵盖了基于链接问题的场景的多个方面,并且可以作为面临相同问题(编码、加密、填充...)的任何人的参考。 15=]
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
Python代码中IV判断错误,应修改如下:
keyiv = KDF.PBKDF2(key, salt, 48, 1000) key = keyiv[:32] iv = keyiv[32:48]
此外,PKCS7 padding is used in the C# code, so that unpadding is necessary in the Python code during decryption. One possibility is
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
) encoded data are encrypted. The data are preceded by a 2 byte BOM(0xFFFE
)。UTF-16LE解码时会自动去掉这个BOM。Python代码中的方法
decode_base64
好像是从here沿袭过来的。此方法应重建丢失的 Base64 填充。我不太确定为什么这里有必要这样做。此外,调用方法时密文的 UTF-16 编码对我来说似乎毫无意义。其实一个简单的Base64解码密文应该就够了:import base64 ... enc_txt = base64.b64decode(data)
但也许我错过了这里的某些方面。
@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