Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/340.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python AES加密提供与原始C#代码不同的结果_Python_C#_Encryption_Aes_Pycryptodome - Fatal编程技术网

Python AES加密提供与原始C#代码不同的结果

Python AES加密提供与原始C#代码不同的结果,python,c#,encryption,aes,pycryptodome,Python,C#,Encryption,Aes,Pycryptodome,C#代码使用AES加密字节数组 我已经使用PyCryptodome编写了一个Python程序来做同样的事情,但是加密的字节总是与我使用C#代码时的结果不同,我确保: 将两种情况下的IV设置为相同的值(仅用于测试目的) 确保这两种情况下的密钥相同 确保原始数据相同 我加密的是:一个字节数组。字节主要表示TLD格式的数据 Python程序将是实用程序的一部分,该实用程序将动态生成流,这些流将由用C#编写的Web应用程序处理 使用,我实际上可以解密C代码生成的字节,并验证它使用的是AES,以及原始

C#代码使用AES加密字节数组

我已经使用PyCryptodome编写了一个Python程序来做同样的事情,但是加密的字节总是与我使用C#代码时的结果不同,我确保:

  • 将两种情况下的IV设置为相同的值(仅用于测试目的)
  • 确保这两种情况下的密钥相同
  • 确保原始数据相同
我加密的是:一个字节数组。字节主要表示TLD格式的数据

Python程序将是实用程序的一部分,该实用程序将动态生成流,这些流将由用C#编写的Web应用程序处理

使用,我实际上可以解密C代码生成的字节,并验证它使用的是AES,以及原始数据是否正确

问题是:还有什么其他的区别因素

Python代码片段:

      from Crypto.Cipher import AES
      from Crypto import Random
      from Crypto.Util.Padding import pad

**** Correction ***
        aes_cipher = AES.new(bytes(key, 'UTF-8'), AES.MODE_CBC)
#
# Correct, the above call would use a random IV value.
# For debugging & learning purpose, I halted this in the 
# debugger and manually set 
# aes_cipher.IV = <a given value>
# and used the same IV in the C# code to try and keep all known inputs identical.
# 
        aes_cipher.block_size = 128
        aes_cipher.key_size = 128   # bits
        encrypted_pack = aes_cipher.encrypt(pad(pack, 16))

        # Tack on to the beginning the 16 bytes of the "IV"

        # FYI - the C# decryption function strips off the first 16 IV bytes
        encrypted_pack = aes_cipher.IV + encrypted_pack

        return encrypted_pack
从加密密码导入AES
从加密导入随机
从Crypto.Util.Padding导入垫
****更正***
aes_cipher=aes.new(字节(键“UTF-8”),aes.MODE_CBC)
#
#正确,上述调用将使用随机IV值。
#出于调试和学习的目的,我在
#调试器和手动设置
#aes_cipher.IV=
#并在C#代码中使用相同的IV来尝试保持所有已知输入相同。
# 
aes_cipher.block_size=128
aes_cipher.key_size=128位
encrypted_pack=aes_cipher.encrypt(pad(pack,16))
#将“IV”的16个字节附加到开头
#仅供参考-C#解密函数去掉了前16个IV字节
加密的\u包=aes\u cipher.IV+加密的\u包
返回加密包
C#片段

aesciper=new RijndaelManaged();
AesCipher.KeySize=128;//192, 256
//块大小:128位==16字节。
//128位是RijndaelManaged的默认值
AESChipher.BlockSize=128;
aesciper.Mode=CipherMode.CBC;
AESChipher.Padding=PaddingMode.zero;
...
...
# 
#是的,GenerateIV()生成一个随机IV。
#如上所述,我通过设置
#第四章=
# 
aessipher.GenerateIV();
设置键(键);//将十进制数字字符串转换为十六进制数字字符串
ICryptoTransform transform=aesciper.CreateEncryptor();
字节[]加密=transform.TransformFinalBlock(buf,0,buf.Length);
字节[]结果=新字节[encrypted.Length+16];
块拷贝(AESChipher.IV,0,result,0,16);
Buffer.BlockCopy(加密的,0,结果,16,加密的.Length);
返回结果;
***
更新
***
我刚刚发现并解决了另一个问题。
密钥被保存为32字节而不是16字节字节的bytearray,这可以解释与在线工具结果的巨大差异。
轻松解决
```byte_key=binascii.unhexlify(key)
一旦我这样做了,两段代码返回的结果就匹配了,它们也匹配了在线工具中的内容。
偷偷摸摸,因为在调试器中,很容易漏掉,因为值看起来相同。
AESChipher.GenerateIV()正在生成一个随机IV,如果我没记错的话。这与

将两种情况下的IV设置为相同的值(仅用于测试目的)

的默认填充是

样式(字符串)–填充算法。它可以是“pkcs7”(默认值)、“iso7816”或“x923”

这与:

AesCipher.Padding = PaddingMode.Zeros;
完全工作的C#和Python示例:

public static byte[] SimpleEncryptAesVariableLengthCbcZeros(string key, byte[] iv, byte[] plain)
{
    byte[] key2 = Encoding.UTF8.GetBytes(key);

    if (key.Length == 0 || key.Length > 32)
    {
        throw new ApplicationException("Illegal length for key");
    }

    int keySize = key2.Length <= 16 ? 128 : key2.Length <= 24 ? 192 : 256;

    using (var aesCipher = new RijndaelManaged())
    {
        aesCipher.KeySize = keySize;

        // BlockSize: 128-bit == 16 bytes. 
        // 128-bit is the default for RijndaelManaged
        aesCipher.BlockSize = 128;

        aesCipher.Mode = CipherMode.CBC;
        aesCipher.Padding = PaddingMode.Zeros;

        if (iv == null)
        {
            // IV as calculated by http://aes.online-domain-tools.com/
            // SHA1(key) truncated to 16 bytes
            iv = SHA1.HashData(key2);
            Array.Resize(ref iv, aesCipher.BlockSize / 8);
        }
        else if (iv.Length != aesCipher.BlockSize / 8)
        {
            throw new ApplicationException("Illegal length for IV");
        }

        aesCipher.IV = iv;

        // Key is padded with bytes set to 0
        Array.Resize(ref key2, aesCipher.KeySize / 8);
        aesCipher.Key = key2;

        using (var encryptor = aesCipher.CreateEncryptor())
        {
            var encrypted = encryptor.TransformFinalBlock(plain, 0, plain.Length);

            var iv_encrypted = new byte[iv.Length + encrypted.Length];
            Array.Copy(iv, 0, iv_encrypted, 0, iv.Length);
            Array.Copy(encrypted, 0, iv_encrypted, iv.Length, encrypted.Length);
            return iv_encrypted;
        }
    }
}

// https://stackoverflow.com/a/311179/613130
public static byte[] StringToByteArray(string hex)
{
    hex = hex.Replace(" ", string.Empty);

    byte[] bytes = new byte[hex.Length / 2];

    for (int i = 0; i < hex.Length; i += 2)
    {
        bytes[i / 2] = Convert.ToByte(hex.Substring(i, 2), 16);
    }

    return bytes;
}

public static string ByteArrayToString(byte[] bytes, string join)
{
    string res = string.Join(join, Array.ConvertAll(bytes, x => x.ToString("x2")));
    return res;
}


static void Main(string[] args)
{
    string key = "abcdefghabcdefghabcdefghabcdefgh";
    byte[] plain = StringToByteArray("0000000000000000000000000000000001");
    var res = SimpleEncryptAesVariableLengthCbcZeros(key, null, plain);
    var res2 = ByteArrayToString(res, " ");
    Console.WriteLine(res2);
}
公共静态字节[]SimpleEncryptAesVariableLengthCbcZeros(字符串键,字节[]iv,字节[]普通)
{
字节[]键2=编码.UTF8.GetBytes(键);
如果(key.Length==0 | | key.Length>32)
{
抛出新的ApplicationException(“密钥长度非法”);
}
int keySize=key2.长度32:
引发异常(“键的长度非法”)

如果len(key2)
aesciper.GenerateIV()
正在生成一个随机IV(如果我没记错的话),则keySize=128。这与将IV设置为两者中的相同值不同(仅用于测试目的),我不确定是什么
aes\u cipher.encrypt(pad(pack,16))
,但这听起来几乎像是在填充数据,然后对其进行加密。我不是Python程序员,所以我可能错了,但这只是听起来的样子。另一方面,你的C#代码肯定是在加密数据,然后将其复制到结果数组中的偏移位置。与问题中的描述相反,随机也用于Python代码中,因为在实例化AES对象s时,第3个参数中没有传递IV。@John-我知道如果我不填充输入,那么我将得到一个异常“数据必须在CBC模式下填充到128字节边界”您的密钥在代码段中的解码方式可能也不同,但您没有在此处显示该代码。请再次检查。此外,如果显式传入密钥,则不应设置密钥大小。将使用该密钥。如果设置密钥大小,则库很可能会出现错误,并为您生成新密钥。这是正确的这将生成一个随机IV。我将在问题中添加一个澄清,即即使我单步执行代码并使用特定值覆盖IV(与C#代码中使用的值相同),最终结果不同。@是否修复了填充?若要检查是否是填充,请尝试加密至少32字节的块。您加密的是什么?文本?如果是,则加密的文本编码方式相同?(UTF8或Unicode)@xanatos-你能解释一下你的建议是什么意思吗?@Guy
aesciper.Padding=PaddingMode.PKCS7
public static byte[] SimpleEncryptAesVariableLengthCbcZeros(string key, byte[] iv, byte[] plain)
{
    byte[] key2 = Encoding.UTF8.GetBytes(key);

    if (key.Length == 0 || key.Length > 32)
    {
        throw new ApplicationException("Illegal length for key");
    }

    int keySize = key2.Length <= 16 ? 128 : key2.Length <= 24 ? 192 : 256;

    using (var aesCipher = new RijndaelManaged())
    {
        aesCipher.KeySize = keySize;

        // BlockSize: 128-bit == 16 bytes. 
        // 128-bit is the default for RijndaelManaged
        aesCipher.BlockSize = 128;

        aesCipher.Mode = CipherMode.CBC;
        aesCipher.Padding = PaddingMode.Zeros;

        if (iv == null)
        {
            // IV as calculated by http://aes.online-domain-tools.com/
            // SHA1(key) truncated to 16 bytes
            iv = SHA1.HashData(key2);
            Array.Resize(ref iv, aesCipher.BlockSize / 8);
        }
        else if (iv.Length != aesCipher.BlockSize / 8)
        {
            throw new ApplicationException("Illegal length for IV");
        }

        aesCipher.IV = iv;

        // Key is padded with bytes set to 0
        Array.Resize(ref key2, aesCipher.KeySize / 8);
        aesCipher.Key = key2;

        using (var encryptor = aesCipher.CreateEncryptor())
        {
            var encrypted = encryptor.TransformFinalBlock(plain, 0, plain.Length);

            var iv_encrypted = new byte[iv.Length + encrypted.Length];
            Array.Copy(iv, 0, iv_encrypted, 0, iv.Length);
            Array.Copy(encrypted, 0, iv_encrypted, iv.Length, encrypted.Length);
            return iv_encrypted;
        }
    }
}

// https://stackoverflow.com/a/311179/613130
public static byte[] StringToByteArray(string hex)
{
    hex = hex.Replace(" ", string.Empty);

    byte[] bytes = new byte[hex.Length / 2];

    for (int i = 0; i < hex.Length; i += 2)
    {
        bytes[i / 2] = Convert.ToByte(hex.Substring(i, 2), 16);
    }

    return bytes;
}

public static string ByteArrayToString(byte[] bytes, string join)
{
    string res = string.Join(join, Array.ConvertAll(bytes, x => x.ToString("x2")));
    return res;
}


static void Main(string[] args)
{
    string key = "abcdefghabcdefghabcdefghabcdefgh";
    byte[] plain = StringToByteArray("0000000000000000000000000000000001");
    var res = SimpleEncryptAesVariableLengthCbcZeros(key, null, plain);
    var res2 = ByteArrayToString(res, " ");
    Console.WriteLine(res2);
}
from Crypto.Cipher import AES
from Crypto import Random
import hashlib 
#from Crypto.Util.Padding import pad

#key must be string
#iv must be bytes or None
#plain must be bytes
def SimpleEncryptAesVariableLengthCbcZeros(key, iv, plain):
    key2 = bytes(key, 'UTF-8')
    
    if len(key2) == 0 or len(key2) > 32:
        raise Exception('Illegal length for key')

    keySize = 128 if len(key2) <= 16 else 192 if len(key2) <= 24 else 256

    if iv == None:
        #IV as calculated by http://aes.online-domain-tools.com/
        #SHA1(key) truncated to 16 bytes
        h = hashlib.sha1()
        h.update(key2)

        iv = h.digest()
        iv = iv[0:16]
    elif len(iv) != 128 // 8:
        raise Exception('Illegal length for iv')

    #Key is padded with bytes set to 0
    key2 = key2 + b'\0' * (keySize // 8 - len(key2))

    aes_cipher = AES.new(key2, AES.MODE_CBC, iv)

    aes_cipher.key_size = keySize
    aes_cipher.block_size = 128

    padded = plain
    
    #zero padding
    if len(padded) % 16 != 0:
        padded = padded + b'\0' * (16 - len(padded) % 16)

    encrypted = aes_cipher.encrypt(bytes(padded))

    iv_encrypted = iv + encrypted

    return iv_encrypted

key = 'abcdefghabcdefghabcdefghabcdefgh'
plain = bytearray.fromhex('0000000000000000000000000000000001')
iv_encrypted = SimpleEncryptAesVariableLengthCbcZeros(key, None, plain)
print(' '.join(["{:02x}".format(x) for x in iv_encrypted]))