2

I have an existing data format that has portions of it encrypted in what appears to be AES in CFB mode. The plaintext data length and the encrypted data length are the same.

In C#, pretty much every angle I've taken seems to expect the encrypted length to be a multiple of the block size... so I get an exception trying to decrypt the data.

In researching solutions, I've used Crypto++ and wrote a quick C++ app that successfully decrypts the data, so I'm pretty sure I'm using the right algorithm, key and IV. This works fine, but I'd like to keep everything inside C# if at all possible. Any suggestions?

Working C++ code below:

//define key
unsigned char key[16];
//populate key
//...


//define iv
unsigned char iv[16];
//populate iv
//...

std::ifstream inFile;

//open file
inFile.open("file.aes",ios::binary );

//get file size
inFile.seekg(0,ios::end);
int fileSize = (int) inFile.tellg();
inFile.seekg(offset, ios::beg);

//read/close file
char* inBytes = new char[fileSize];
inFile.read(inBytes,fileSize);
inFile.close();

//configure decryption
CFB_Mode<AES>::Decryption cfbDecryption(key, 16, iv);

//populate output bytes
char* outBytes = new char[fileSize];
cfbDecryption.ProcessData((byte*) outBytes,(byte*) inBytes,fileSize);

//open/write/close output file
std::ofstream outFile;
outFile.open("out.dec");
outFile.write(outBytes,fileSize);
outFile.close();

delete[] inBytes;
magnvs
  • 63
  • 1
  • 9

2 Answers2

4

Here is an example showing how to use the RijndaelManaged class to achieve 8-bit feedback CFB encryption. AesManaged does not support CFB because, I believe, the official NIST AES does not support it. By noting that AES is just Rijndael restricted to the 128 bit blocksize and the 128, 192, and 256 bit keysizes you can use the RijndaelManaged classes to get your CFB functionality. NOTE: I'm not a C# or .NET expert so improvements are welcome.

using System;
using System.Text;
using System.Security.Cryptography;
using System.IO;

namespace AesCFB8Mode
{
    class AESCFB8Example
    {
        static void Example()
        {
            //
            // Encrypt a small sample of data
            //
            String Plain = "The quick brown fox";
            byte[] plainBytes = Encoding.UTF8.GetBytes(Plain);
            Console.WriteLine("plaintext length is " + plainBytes.Length);
            Console.WriteLine("Plaintext is " + BitConverter.ToString(plainBytes));

            byte [] savedKey = new byte[16];
            byte [] savedIV = new byte[16];
            byte[] cipherBytes;
            using (RijndaelManaged Aes128 = new RijndaelManaged())
            {
                //
                // Specify a blocksize of 128, and a key size of 128, which make this
                // instance of RijndaelManaged an instance of AES 128.
                //
                Aes128.BlockSize = 128;
                Aes128.KeySize = 128;

                //
                // Specify CFB8 mode
                //
                Aes128.Mode = CipherMode.CFB;
                Aes128.FeedbackSize = 8;
                Aes128.Padding = PaddingMode.None;
                //
                // Generate and save random key and IV.
                //
                Aes128.GenerateKey();
                Aes128.GenerateIV();

                Aes128.Key.CopyTo(savedKey, 0);
                Aes128.IV.CopyTo(savedIV, 0);

                using (var encryptor = Aes128.CreateEncryptor())
                using (var msEncrypt = new MemoryStream())
                using (var csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
                using (var bw = new BinaryWriter(csEncrypt, Encoding.UTF8))
                {
                    bw.Write(plainBytes);
                    bw.Close();

                    cipherBytes = msEncrypt.ToArray();
                    Console.WriteLine("Cipher length is " + cipherBytes.Length);
                    Console.WriteLine("Cipher text is " + BitConverter.ToString(cipherBytes));
                }
            }

            //
            // Now decrypt the cipher back to plaintext
            //

            using (RijndaelManaged Aes128 = new RijndaelManaged())
            {
                Aes128.BlockSize = 128;
                Aes128.KeySize = 128;
                Aes128.Mode = CipherMode.CFB;
                Aes128.FeedbackSize = 8;
                Aes128.Padding = PaddingMode.None;

                Aes128.Key = savedKey;
                Aes128.IV = savedIV;

                using (var decryptor = Aes128.CreateDecryptor())
                using (var msEncrypt = new MemoryStream(cipherBytes))
                using (var csEncrypt = new CryptoStream(msEncrypt, decryptor, CryptoStreamMode.Read))
                using (var br = new BinaryReader(csEncrypt, Encoding.UTF8))
                {
                    //csEncrypt.FlushFinalBlock();
                    plainBytes = br.ReadBytes(cipherBytes.Length);

                    Console.WriteLine("Decrypted plain length is " + plainBytes.Length);
                    Console.WriteLine("Decrypted plain text bytes is " + BitConverter.ToString(plainBytes));
                    Console.WriteLine("Decrypted plain text is " + Encoding.UTF8.GetString(plainBytes));
                }
            }
        }

        static void Main(string[] args)
        {
            Example();
        }
    }
}
pwhe23
  • 1,196
  • 1
  • 14
  • 15
President James K. Polk
  • 40,516
  • 21
  • 95
  • 125
  • 1
    thanks for the response... i tried using the decryption portion of the code you provided. while it was able to decrypt the data without throwing an exception, it did not return the correct plaintext for what i have encrypted. – magnvs Mar 05 '12 at 14:52
  • @pwhe23: Nice edit, thank you for improving the answer. – President James K. Polk Dec 04 '19 at 22:50
0

I revisited trying to use cryptlib and it solved my problem... code is below:

using cryptlib;

byte[] key = new byte[16] {...key bytes here...};

byte[] iv =  new byte[16] {...iv bytes here...};

byte[] enc;  //ciphertext bytes (i populated them from a filestream)

crypt.Init();
int cryptContext = crypt.CreateContext(crypt.UNUSED, crypt.ALGO_AES);
crypt.SetAttribute(cryptContext, crypt.CTXINFO_MODE, crypt.MODE_CFB);
crypt.SetAttributeString(cryptContext, crypt.CTXINFO_KEY, key, 0, 16);
crypt.SetAttributeString(cryptContext, crypt.CTXINFO_IV, iv, 0, 16);
crypt.Decrypt(cryptContext, enc);   //ciphertext bytes replaced with plaintext bytes
crypt.DestroyContext(cryptContext);
magnvs
  • 63
  • 1
  • 9