1

I need to perform encryption array of byte []. I used the example available on the Microsoft. Unfortunately, the encrypted data is truncated to the size that is a multiple of 16. If, in the example of the data I will add 8 times byte 0, the data will be encrypted properly. Padding has been set, but I do not see anything to change it. How to solve this problem, the data do not become cut off.

public byte[] EncryptAES(byte[] plainBytes)
{
    System.Text.ASCIIEncoding encoding = new System.Text.ASCIIEncoding();
    byte[] FKey = encoding.GetBytes("A002AD9AD73C402190C3E733D82CEA00");
    byte[] FIV = encoding.GetBytes("zyxwvutsrqponmlk");

    // Check arguments.
    if (plainBytes == null || plainBytes.Length <= 0)
        throw new ArgumentNullException("plainText");
    if (FKey == null || FKey.Length <= 0)
        throw new ArgumentNullException("Key");
    if (FIV == null || FIV.Length <= 0)
        throw new ArgumentNullException("Key");
    byte[] encrypted;
    // Create an RijndaelManaged object
    // with the specified key and IV.
    using (RijndaelManaged rijAlg = new RijndaelManaged())
    {
        rijAlg.Key = FKey;
        rijAlg.IV = FIV;
        rijAlg.Padding = PaddingMode.Zeros;
        rijAlg.Mode = CipherMode.CBC;

        // Create a decrytor to perform the stream transform.
        ICryptoTransform encryptor = rijAlg.CreateEncryptor(rijAlg.Key, rijAlg.IV);

        // Create the streams used for encryption.
        using (MemoryStream msEncrypt = new MemoryStream())
        {
            using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
            {
                // plainBytes.Length = 2216 
                csEncrypt.Write(plainBytes, 0, plainBytes.Length);

                // encrypted.Length = 2208
                encrypted = msEncrypt.ToArray();
            }
        }
    }

    // Return the encrypted bytes from the memory stream.
    return encrypted;
}
Emil J
  • 215
  • 2
  • 4
  • 20
  • Hi Emil, could you share the link where you attained the source code example please? – Mr. Mr. Mar 08 '13 at 10:21
  • @Mr.Mr. It may help you (https://msdn.microsoft.com/en-us/library/system.security.cryptography.aes(v=vs.110).aspx) – M at Sep 04 '16 at 15:51

4 Answers4

2

CryptoStream:

You should always explicitly close your CryptoStream object after you are done using it by calling the Close method. Doing so flushes the stream and causes all remain blocks of data to be processed by the CryptoStream object. However, if an exception occurs before you call the Close method, the CryptoStream object might not be closed. To ensure that the Close method always gets called, place your call to the Close method within the finally block of a try/catch statement.

(My emphasis)

So, call Close before you try to do anything with the results.


Basically, padding is used to deal with the last block of a sequence of encrypted blocks. Since the CryptoStream doesn't know how many times you intend to call Write(), it doesn't apply padding or write any final incomplete block until you call Close.

(Or, as Monkieboy points out, FlushFinalBlock can also be used to indicate that you're finished)

Damien_The_Unbeliever
  • 234,701
  • 27
  • 340
  • 448
  • I thought that this is not required if I use block using {}. Can you show the code where you need to take advantage of the option Close ()? – Emil J Mar 08 '13 at 10:47
  • @EmilJ - You need to do it *somewhere* before you do `msEncrypt.ToArray`. It can be either `Close` or `Dispose` (or `using`), they're equivalent in this case – Damien_The_Unbeliever Mar 08 '13 at 10:51
  • Thank you. Subject to closing. You saved me a lot of time. – Emil J Mar 08 '13 at 10:52
  • I thought the `csEncrypt.FlushFinalBlock();` just after `csEncrypt.Write(plainBytes, 0, plainBytes.Length);` would work? – Mr. Mr. Mar 08 '13 at 11:05
  • @Monkieboy - yes, that would also work. It's strange - I was sure something along those lines was available, but I swear I looked through the methods twice or thrice and couldn't see it. – Damien_The_Unbeliever Mar 08 '13 at 11:57
2

Just calling FlushFinalBlock() resolves the multiple of 16 problem.

1

try this

    using (MemoryStream msEncrypt = new MemoryStream())
    {
        using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
        {
            csEncrypt.Write(plainBytes, 0, plainBytes.Length);
        }
        encrypted = msEncrypt.ToArray();
    }
polybios
  • 1,159
  • 8
  • 20
  • After all, exactly as I do, and it does not help. The problem is somewhere in the last block of data (no padding). – Emil J Mar 08 '13 at 10:48
  • @EmilJ - No, it's *not* exactly as you do - they're waiting until `csEncrypt` has been `Dispose`d (or `Close`d, as per my answer), *before* accessing the encrypted data. – Damien_The_Unbeliever Mar 08 '13 at 10:51
0

It is also important to be careful while decrypting data with CryptoStream. It is advisable to read it using a loop. Calling Read only once can lead to truncated results.

using (var crypto = new CryptoStream(stream, decryptor, CryptoStreamMode.Read))
{
    plainTextBytes = new byte[cleanCipherBytes.Length];

    int read = 0, rem = plainTextBytes.Length;

    do
    {
        read = crypto.Read(plainTextBytes, read, rem);
        rem -= read;
    }
    while (read > 0);
}

This took me quite a while to figure out. I hope it saves someone else's time.

Prince Owen
  • 1,225
  • 12
  • 20