在python

时间:2019-06-25 01:37:38

标签: c# python aes

我有一个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

2 个答案:

答案 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字节BOM0xFFFE)。在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