AES 128 CBC encrypt decrypt size problems

"C. Collis" <[email protected]> Fri, 21 Nov 2008 11:02:54 +0100
Newsgroups gmane.comp.python.cryptography
Message-ID <LISTSERV%[email protected]>
Hey,

I'm trying to implement rfc 3566 in Python using M2Crypto.

There seem to be some issues however!


Given this python code:
--------------------------------------
from M2Crypto import EVP
import StringIO

def encrypt(data, key, iv):
    buffer =3D StringIO.StringIO()
    cipher =3D EVP.Cipher('aes_128_cbc', key=3Dkey, iv=3Div, op=3D1)
    buffer.write(cipher.update(data))
    buffer.write(cipher.final())
    data =3D buffer.getvalue()

    return data


def decrypt(data, key, iv):
    buffer =3D StringIO.StringIO()
    cipher =3D EVP.Cipher('aes_128_cbc', key=3Dkey, iv=3Div, op=3D0)
    buffer.write(cipher.update(data))
    buffer.write(cipher.final())
    data =3D buffer.getvalue()
=20=20=20=20
    return data

key =3D bytearray('\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x=
0d\x0e\x0f')
pt =3D bytearray('\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x0=
1\x01\x01')
iv =3D bytearray('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0=
0\x00\x00')
ct =3D encrypt(pt, key, iv)

print "PT Len:", len(pt), "Data: ", repr([hex(x) for x in pt])
print "CT Len:", len(ct), "Data: ", repr([hex(ord(x)) for x in ct])

pt2 =3D decrypt(ct, key, iv)

assert pt =3D=3D pt2

--------------------------------------

The CT len is 32 bytes! According to the RFC it should be only 16 bytes. =
I tried exactly the same test in=20
C# .NET using the System.Security.Cryptography library and I get the corr=
ect, expected 16 byte CT=20
value.

What is strange is that M2Crypto and C# produce the same first 16 bytes o=
f encrypted data, but=20
M2Crypto then adds another 16 bytes of junk to the end!

If I try and decrypt the CT data (32 bytes) that M2Crypto produces in C#,=
 I get a 32 byte PT value=20
where the first 16 bytes are the correct value and the second 16 bytes ar=
e junk!

If I try the other way around and use the encrypted CT data from C# (16 b=
ytes) and try and decrypt it=20
using M2Crypto I get a 15 byte PT value that is correct but missing the l=
ast byte!

Why is M2Crypto doubling the size of my PT when encrypting and why can't =
it handle a 16 byte CT value=20
correctly? In C# I can decrypt the 16 byte CT value back to the 16 byte P=
T value as expected.

This is making it impossible to implement the RFC as M2Crypto doesn't app=
ear to produce the correct=20
results for AES-128-CBC mode encryption! While M2Crypto can encrypt and d=
ecrypt data processed by=20
itself it is unable to work with other crypto implementations, what am I =
missing?


The C# Program is:


---------------------------
using System;
using System.IO;
using System.Security.Cryptography;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            EncryptK1();
            DecryptPythonK1CT();
            Console.ReadKey();
        }

        static byte[] K1 =3D new byte[] { 0x01, 0x01, 0x01, 0x01, 0x01, 0=
x01, 0x01, 0x01, 0x01, 0x01, 0x01,=20
0x01, 0x01, 0x01, 0x01, 0x01 };
        static byte[] IV =3D new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0=
x00, 0x00, 0x00, 0x00, 0x00, 0x00,=20
0x00, 0x00, 0x00, 0x00, 0x00 };
        static byte[] KEY =3D new byte[] { 0x00, 0x01, 0x02, 0x03, 0x04, =
0x05, 0x06, 0x07, 0x08, 0x09,=20
0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f };


        public static void DecryptPythonK1CT()
        {
            Console.WriteLine("Decrypting Python Encrypted K1 Value using=
 C#...");

            byte[] ct =3D new byte[] { 195, 82, 128, 87, 84, 35, 127, 49,=
 26, 192, 255, 244, 227, 224, 62,=20
120, 169, 125, 222, 82, 14, 200, 65, 189, 3, 69, 101, 3, 189, 71, 131, 14=
4 };

            byte[] pt =3D Decrypt(KEY, IV, ct);

            Console.Write("K1 Python CT:\t");
            Print(ct);

            Console.Write("K1 C# PT:\t");
            Print(pt);

            Console.WriteLine("");
        }


        public static void EncryptK1()
        {
            Console.WriteLine("Encrypting K1 Value using C#...");

            byte[] ct =3D Encrypt(KEY, IV, K1);

            Console.Write("K1 PT:\t\t");
            Print(K1);

            Console.Write("K1 C# CT:\t");
            Print(ct);

            Console.WriteLine("");
        }


        static private void Print(byte[] b)
        {
            for (int i =3D 0; i < b.Length; i++)
            {
                Console.Write(string.Format("{0:X}", b[i]));
            }

            Console.WriteLine();
        }


        private static byte[] Encrypt(byte[] key, byte[] iv, byte[] data)=

        {
            byte[] ciphertext =3D new byte[0];

            Rijndael cipher =3D RijndaelManaged.Create();
            cipher.Padding =3D PaddingMode.None;
            cipher.Mode =3D CipherMode.CBC;

            ICryptoTransform encryptor =3D cipher.CreateEncryptor(key, iv=
);

            using (MemoryStream memoryStream =3D new MemoryStream())
            {
                using (CryptoStream cryptoStream =3D new CryptoStream(
                    memoryStream, encryptor, CryptoStreamMode.Write))
                {
                    cryptoStream.Write(data, 0, data.Length);

                    cryptoStream.FlushFinalBlock();

                    ciphertext =3D memoryStream.ToArray();
                }
            }

            return ciphertext;
        }



        private static byte[] Decrypt(byte[] key, byte[] iv, byte[] data)=

        {
            byte[] plaintext =3D new byte[0];

            Rijndael cipher =3D RijndaelManaged.Create();
            cipher.Padding =3D PaddingMode.None;
            cipher.Mode =3D CipherMode.CBC;

            ICryptoTransform decryptor =3D cipher.CreateDecryptor(key, iv=
);

            using (MemoryStream memoryStream =3D new MemoryStream())
            {
                using (CryptoStream cryptoStream =3D new CryptoStream(
                    memoryStream, decryptor, CryptoStreamMode.Write))
                {

                    cryptoStream.Write(data, 0, data.Length);

                    cryptoStream.FlushFinalBlock();

                    plaintext =3D memoryStream.ToArray();
                }
            }

            return plaintext;
        }
    }
}
---------------------------

The output of this C# program is:

-----------------------
Encrypting K1 Value using C#...
K1 PT:          1111111111111111
K1 C# CT:     C352805754237F311AC0FFF4E3E03E78

Decrypting Python Encrypted K1 Value using C#...
K1 Python CT:  C352805754237F311AC0FFF4E3E03E78A97DDE52EC841BD345653BD478=
390
K1 C# PT:       111111111111111110101010101010101010101010101010
-----------------------

Any help greatly appriciated!!

Thanks