[PYTHON-CRYPTO] AES 128 CBC encrypt decrypt size problems
C. Collis
koniosis at GMAIL.COM
Fri Nov 21 11:02:54 CET 2008
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 = StringIO.StringIO()
cipher = EVP.Cipher('aes_128_cbc', key=key, iv=iv, op=1)
buffer.write(cipher.update(data))
buffer.write(cipher.final())
data = buffer.getvalue()
return data
def decrypt(data, key, iv):
buffer = StringIO.StringIO()
cipher = EVP.Cipher('aes_128_cbc', key=key, iv=iv, op=0)
buffer.write(cipher.update(data))
buffer.write(cipher.final())
data = buffer.getvalue()
return data
key = bytearray('\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f')
pt = bytearray('\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01')
iv = bytearray('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')
ct = 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 = decrypt(ct, key, iv)
assert pt == pt2
--------------------------------------
The CT len is 32 bytes! According to the RFC it should be only 16 bytes. I tried exactly the same test in
C# .NET using the System.Security.Cryptography library and I get the correct, expected 16 byte CT
value.
What is strange is that M2Crypto and C# produce the same first 16 bytes of encrypted data, but
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
where the first 16 bytes are the correct value and the second 16 bytes are junk!
If I try the other way around and use the encrypted CT data from C# (16 bytes) and try and decrypt it
using M2Crypto I get a 15 byte PT value that is correct but missing the last byte!
Why is M2Crypto doubling the size of my PT when encrypting and why can't it handle a 16 byte CT value
correctly? In C# I can decrypt the 16 byte CT value back to the 16 byte PT value as expected.
This is making it impossible to implement the RFC as M2Crypto doesn't appear to produce the correct
results for AES-128-CBC mode encryption! While M2Crypto can encrypt and decrypt data processed by
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 = new byte[] { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01 };
static byte[] IV = new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00 };
static byte[] KEY = new byte[] { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f };
public static void DecryptPythonK1CT()
{
Console.WriteLine("Decrypting Python Encrypted K1 Value using C#...");
byte[] ct = new byte[] { 195, 82, 128, 87, 84, 35, 127, 49, 26, 192, 255, 244, 227, 224, 62,
120, 169, 125, 222, 82, 14, 200, 65, 189, 3, 69, 101, 3, 189, 71, 131, 144 };
byte[] pt = 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 = 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 = 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 = new byte[0];
Rijndael cipher = RijndaelManaged.Create();
cipher.Padding = PaddingMode.None;
cipher.Mode = CipherMode.CBC;
ICryptoTransform encryptor = cipher.CreateEncryptor(key, iv);
using (MemoryStream memoryStream = new MemoryStream())
{
using (CryptoStream cryptoStream = new CryptoStream(
memoryStream, encryptor, CryptoStreamMode.Write))
{
cryptoStream.Write(data, 0, data.Length);
cryptoStream.FlushFinalBlock();
ciphertext = memoryStream.ToArray();
}
}
return ciphertext;
}
private static byte[] Decrypt(byte[] key, byte[] iv, byte[] data)
{
byte[] plaintext = new byte[0];
Rijndael cipher = RijndaelManaged.Create();
cipher.Padding = PaddingMode.None;
cipher.Mode = CipherMode.CBC;
ICryptoTransform decryptor = cipher.CreateDecryptor(key, iv);
using (MemoryStream memoryStream = new MemoryStream())
{
using (CryptoStream cryptoStream = new CryptoStream(
memoryStream, decryptor, CryptoStreamMode.Write))
{
cryptoStream.Write(data, 0, data.Length);
cryptoStream.FlushFinalBlock();
plaintext = 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: C352805754237F311AC0FFF4E3E03E78A97DDE52EC841BD345653BD478390
K1 C# PT: 111111111111111110101010101010101010101010101010
-----------------------
Any help greatly appriciated!!
Thanks
More information about the python-crypto
mailing list