Consider the following code and output:
public static void Main() {
DESCryptoServiceProvider symAlg = new DESCryptoServiceProvider();
symAlg.BlockSize = 64;
symAlg.GenerateKey();
symAlg.Mode = CipherMode.ECB;
testCipher(symAlg, new byte[] {
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08
});
testCipher(symAlg, new byte[] {
0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8,
0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8,
0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0x8E,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
});
Console.ReadKey();
}
public static void testCipher(SymmetricAlgorithm symAlg, byte[] plainText) {
ICryptoTransform xfrm;
xfrm = symAlg.CreateEncryptor();
byte[] encrypted = xfrm.TransformFinalBlock(plainText, 0, plainText.Length);
xfrm = symAlg.CreateDecryptor();
byte[] decrypted = xfrm.TransformFinalBlock(encrypted, 0, encrypted.Length);
Console.WriteLine(new string('=', 23));
writeBlocks(plainText);
writeBlocks(encrypted);
writeBlocks(decrypted);
}
private static void writeBlocks(byte[] blocks){
for (int i = 0; i < blocks.Length; i += 8) Console.WriteLine(BitConverter.ToString(blocks, i, 8));
Console.WriteLine();
}
Output:
=======================
01-02-03-04-05-06-07-08
01-02-03-04-05-06-07-08
1E-0C-3E-59-93-5C-23-6E
1E-0C-3E-59-93-5C-23-6E
6F-AC-50-69-34-D0-B1-61 // NOTE THIS
01-02-03-04-05-06-07-08
01-02-03-04-05-06-07-08
=======================
C1-C2-C3-C4-C5-C6-C7-C8
D1-D2-D3-D4-D5-D6-D7-D8
E1-E2-E3-E4-E5-E6-E7-8E
00-00-00-00-00-00-00-00
F9-9A-77-30-3B-31-7F-D2
D8-B5-B2-C6-E7-E7-0F-90
0E-90-DF-AF-56-C0-DE-84
65-5D-E0-7D-5A-7A-0F-D9
6F-AC-50-69-34-D0-B1-61 // AND THIS
C1-C2-C3-C4-C5-C6-C7-C8
D1-D2-D3-D4-D5-D6-D7-D8
E1-E2-E3-E4-E5-E6-E7-8E
00-00-00-00-00-00-00-00
I understand the weakness of ECB. What I don't understand, is why on earth would .NET force me to append a final block that is the length of the key and only varies with the key. No matter how weak the encryption was to start with, isn't this worse?
I have a specific reason for using ECB: Encrypt array of int for individual retrieval
However, decrypting just one block (without the constant final block) yields: System.Security.Cryptography.CryptographicException was unhandled Message=Bad Data.
Now, knowing that it is constant by the key, I can perform a bogus encryption at application initialization and cache the final block, feeding it back in to my decryption operation rather than putting it in the data stream, but why in would .NET encourage me to store this with the data, and is it only .NET that does this?