Search code examples
c#pythonencryptionaes

Convert C# to Python using AES/CBC/NoPadding


I'm trying to convert this C# code to Python (2.7). The problem is that the result of the decryption is wrong with the python code. IV and key is correct.

I found many subjects that talk about Python and C# but i didn't found an answer.

C# encryption:

class Tracer
{
    private static readonly int BlockBitSize = 128;
    private static readonly int KeyBitSize = 256;

    internal static byte[] In(byte[] plainBytes, byte[] uid)
    {
        using (var sha = new SHA512Managed())
        {
            var hash = sha.ComputeHash(uid);
            return In(plainBytes, hash.Skip(32).Take(32).ToArray(), hash.Take(16).ToArray());
        }
    }

    internal static byte[] In(byte[] plainBytes, byte[] key, byte[] iv)
    {
        if (key == null || key.Length != KeyBitSize / 8)
            throw new ArgumentException(String.Format("Key needs to be {0} bit!", KeyBitSize), "key");
        if (iv == null || iv.Length != BlockBitSize / 8)
            throw new ArgumentException(String.Format("IV needs to be {0} bit!", BlockBitSize), "iv");

        using (AesManaged aes = new AesManaged())
        {
            aes.KeySize = KeyBitSize;
            aes.BlockSize = BlockBitSize;
            aes.Mode = CipherMode.CBC;
            aes.Padding = PaddingMode.None;

            using (ICryptoTransform encrypter = aes.CreateEncryptor(key, iv))
                using (MemoryStream cipherStream = new MemoryStream())
                {
                    using (CryptoStream cryptoStream = new CryptoStream(cipherStream, encrypter, CryptoStreamMode.Write))
                    {
                        cryptoStream.Write(plainBytes, 0, plainBytes.Length);
                        cryptoStream.FlushFinalBlock();
                    }
                    return cipherStream.ToArray();
                }
        }
    }

    internal static byte[] Out(byte[] cipherBytes, byte[] uid)
    {
        using (var sha = new SHA512Managed())
        {
            var hash = sha.ComputeHash(uid);
            return Out(cipherBytes, hash.Skip(32).Take(32).ToArray(), hash.Take(16).ToArray());
        }
    }

    internal static byte[] Out(byte[] cipherBytes, byte[] key, byte[] iv)
    {
        if (key == null || key.Length != KeyBitSize / 8)
            throw new ArgumentException(String.Format("Key needs to be {0} bit!", KeyBitSize), "key");
        if (iv == null || iv.Length != BlockBitSize / 8)
            throw new ArgumentException(String.Format("IV needs to be {0} bit!", BlockBitSize), "iv");

        using (AesManaged aes = new AesManaged())
        {
            aes.KeySize = KeyBitSize;
            aes.BlockSize = BlockBitSize;
            aes.Mode = CipherMode.CBC;
            aes.Padding = PaddingMode.None;

            using (ICryptoTransform decrypter = aes.CreateDecryptor(key, iv))
                using (MemoryStream plainStream = new MemoryStream())
                {
                    using (var decrypterStream = new CryptoStream(plainStream, decrypter, CryptoStreamMode.Write))
                        using (var binaryWriter = new BinaryWriter(decrypterStream))
                        {
                            //Decrypt Cipher Text from Message
                            binaryWriter.Write(cipherBytes, 0, cipherBytes.Length);
                        }
                    //Return Plain Text
                    return plainStream.ToArray();
                }
        }
    }
}

Python decryption

def AESdecrypt(ciphertext, UID):

    from Crypto.Cipher import AES

    digest = hashlib.sha512(UID).hexdigest()

    iv = BitArray(hex=digest[:32])

    key = BitArray(hex=digest[64:128])

    block40Str = BitArray(hex=ciphertext[1].encode('hex'))

    cipherSpec = AES.new(key.bytes, AES.MODE_CBC, iv.bytes)
    plaintextWithPadding = cipherSpec.decrypt(block40Str.bytes)

Note : Sorry for my english

Thanks for your help !

EDIT : AES decryption in Python return 64 characters, that is wrong. The original plaintext is 32.

EDIT2: Python code updated. The decrypt function return now 32 characters, but still doing wrong


Solution

  • The digest used to generate the key and the iv was generated with the correct data but in string. Conversely, C# generate the digest with a ByteArray of the data. Thanks to the BitArray Python library , i solve my problem :

    New Python code :

    def AESdecrypt(ciphertext, UID):
    
        from Crypto.Cipher import AES
    
        UIDBytes = BitArray(hex=UID)
        digest = hashlib.sha512(UIDBytes.bytes).hexdigest()
    
        iv = BitArray(hex=digest[:32])
    
        key = BitArray(hex=digest[64:128])
    
        cipherSpec = AES.new(key.bytes, AES.MODE_CBC, iv.bytes)
        plaintextWithoutPadding = cipherSpec.decrypt(ciphertext[1])