I want to claculate the MAC(Message Authentication Code) CBC chiper(Ansi x9.9), i found a sample which calculates the MAC based on a cycle, in each round the encrypted reuslt must be XOR with next round plain Text block and the result should be encrepted to being used to next step and this cycle repeats for 4 times till the last encrypted value must be return as MAC.
Cryptographic Key = 0123456789abcdef
The text is the ASCII code for "7654321 Now is the time for ".
Text = 37363534333231204e6f77206873207468652074696d6520666f7220
TIME --- PLAIN TEXT---------------DES INPUT BLOCK -------- DES OUTPUT BLOCK
1 ---- 3736353433323120 -------- 3736353433323120 -------- 21fb193693a16c28
2 ---- 4e6f772068732074 -------- 6f946e16fad24c5c -------- 6c463f0cb7167a6f
3 ---- 68652074696d6520 -------- 04231f78de7b1f4f -------- 956ee891e889d91e
4 ---- 666f722000000000 -------- f3019ab1e889d91e -------- f1d30f6849312ca4
I tried to implement this sample. at the first step i got the same result as the sample but for the next step my Des encryption function returns the different resutl as the sample's 2th step. i used a hardware device to encrypt each Des input block, it returns the same DES output block as the sample return. either i found another DES implementation sample here it reutrns the correct encrption too. but my app which uses microsft example on msdn returns the incorrect result for steps 2,3 and 4 except step 1. here is my code:
public byte[] EncryptPart(byte[] toEncrypt, byte[] Key, byte[] IV)
{
try
{
MemoryStream mStream = new MemoryStream();
DES DESalg = DES.Create();
DESalg.Mode = CipherMode.CBC;
DESalg.Padding = PaddingMode.None;
CryptoStream cStream = new CryptoStream(mStream,
DESalg.CreateEncryptor(Key, IV),
CryptoStreamMode.Write);
cStream.Write(toEncrypt, 0, toEncrypt.Length);
cStream.FlushFinalBlock();
byte[] ret = mStream.ToArray();
cStream.Close();
mStream.Close();
return ret;
}
catch (CryptographicException e)
{
Console.WriteLine("A Cryptographic error occurred: {0}", e.Message);
return null;
}
}
and here where i have used that function
var IV = new byte[8];//empty byte array
var key = new byte[] { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef };
var result = new byte[8];
int LoopCount = data.Length / 8;
for (int i = 0; i < LoopCount; i++)
{
byte[] Part= new byte[8];
Array.Copy(data, i * 8, Part, 0, 8);
Part = XorArray(Part, result);
result = EncryptPart(Part, key, IV);
}
int remain=data.Length % 8;
if (remain != 0)
{
byte[] LastPart = new byte[8];//
Array.Copy(data, data.Length - remain, LastPart, 0, remain);
LastPart=XorArray(LastPart, result);
result = EncryptPart(LastPart, key, IV);
}
You should reuse the cypher instead of reinitialising it with the key and IV each time.
The calling code:
var IV = new byte[8];//empty byte array
var key = new byte[] { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef };
var data = Encoding.ASCII.GetBytes("7654321 Now is the time for ");
DES DESalg = DES.Create();
DESalg.Mode = CipherMode.CBC;
DESalg.Padding = PaddingMode.None;
ICryptoTransform crypt = DESalg.CreateEncryptor(key, IV);
var result = new byte[8];
int LoopCount = data.Length / 8;
for (int i = 0; i < LoopCount; i++)
{
Console.WriteLine("=============Round {0}==============", i + 1);
byte[] part = new byte[8];
Array.Copy(data, i * 8, part, 0, 8);
Console.WriteLine("Plain text : {0}", ByteArrayToString(part));
part = XorArray(part, result);
Console.WriteLine("DES INPUT : {0}", ByteArrayToString(part));
result = EncryptPart(crypt, part);
}
int remain = data.Length % 8;
if (remain != 0)
{
Console.WriteLine("===========Final Round==============");
byte[] LastPart = new byte[8];//
Array.Copy(data, data.Length - remain, LastPart, 0, remain);
Console.WriteLine("Plain text : " + ByteArrayToString(LastPart));
LastPart = XorArray(LastPart, result);
Console.WriteLine("DES INPUT : " + ByteArrayToString(LastPart));
result = EncryptPart(crypt, LastPart);
}
Console.WriteLine("Result: {0}", ByteArrayToString(result));
And the modified Encrypt part method:
public static byte[] EncryptPart(ICryptoTransform crypt, byte[] toEncrypt)
{
try
{
MemoryStream mStream = new MemoryStream();
CryptoStream cStream = new CryptoStream(mStream,
crypt,
CryptoStreamMode.Write);
cStream.Write(toEncrypt, 0, toEncrypt.Length);
cStream.FlushFinalBlock();
byte[] ret = mStream.ToArray();
cStream.Close();
mStream.Close();
Console.WriteLine("DES OUTPUT : " + ByteArrayToString(ret));
return ret;
}
catch (CryptographicException e)
{
Console.WriteLine("A Cryptographic error occurred: {0}", e.Message);
return null;
}
}
And the results:
=============Round 1==============
Plain text : 3736353433323120
DES INPUT : 3736353433323120
DES OUTPUT : 21fb193693a16c28
=============Round 2==============
Plain text : 4e6f772069732074
DES INPUT : 6f946e16fad24c5c
DES OUTPUT : 6c463f0cb7167a6f
=============Round 3==============
Plain text : 68652074696d6520
DES INPUT : 04231f78de7b1f4f
DES OUTPUT : 956ee891e889d91e
===========Final Round============
Plain text : 666f722000000000
DES INPUT : f3019ab1e889d91e
DES OUTPUT : f1d30f6849312ca4
Result: f1d30f6849312ca4
These values match the ones you specified, and those in this specification