OnlyKing
OnlyKing

Reputation: 3

How to encrypt / decrypt only certain amount of bytes (file)?

I'm implementing encryption/decryption of files, where only certain amount of bytes should be encrypted. For example: I have 500 MB large file and I want to encrypt (and ofcourse decrypt) only 2 MB of file.

I have implemented everything, Encryption works fine (without an error), but when I run Decryption it always throws out this error:

System.Security.Cryptography.CryptographicException: Padding is invalid and cannot be removed.
at System.Security.Cryptography.CapiSymmetricAlgorithm.DepadBlock(Byte[] block, Int32 offset, Int32 count) at  System.Security.Cryptography.CapiSymmetricAlgorithm.TransformFinalBlock(Byte[] inputBuffer, Int32 inputOffset, Int32 inputCount)
at System.Security.Cryptography.CryptoStream.FlushFinalBlock()
at System.Security.Cryptography.CryptoStream.Dispose(Boolean disposing)
at System.IO.Stream.Close()
at System.IO.Stream.Dispose()
at ...

Then I've tried to set the Padding to encryptor.Padding = PaddingMode.None; (and also tried PaddingMode.Zeros, etc.). After running Encryption and Decryption with this Padding modes the result of Decryption is without error/exception, but encrypted part of a file is still encrypted, but a bit different. I've also checked that password is correct

Now I'dont have anymore solutions how to handle this "partial" encryption of files. Any ideas? How to deal with this padding or bytes?

Here is my code of Encryption and Decryption process of certain amount of bytes (sorry for the length, but only that you will know :) ):

static byte[] FILE_HEADER = Encoding.Default.GetBytes("header_of_file"); //this is written to the first line of encrypted file
static long limitBytes = 4096 * 8; //limit encryption to this amount of bytes

public static bool Encrypt(string inputFilePath, string outputfilePath, string EncryptionKey)
{
int bytesRead = 1;
long byteWriteCounter = 0;
long encryptedByteCounter = 0;
byte[] blength = null;
byte[] intBytes = null;
int bufferLen = 4096;
byte[] buffer = new byte[bufferLen];
blength = new byte[FILE_HEADER.Length];
long sumBytesRead = 0;

try
{
    using (FileStream fsInput = new FileStream(inputFilePath, FileMode.Open))
    {                    
        fsInput.Read(blength, 0, blength.Length);

        if (!blength.SequenceEqual(FILE_HEADER)) //read the FILE_HEADER - if not equal that we can encrypt otherwise is already encrypted
        {
            fsInput.Position = 0;

            using (FileStream fsOutput = new FileStream(outputfilePath, FileMode.Create))
            {                            
                using (Aes encryptor = Aes.Create())
                {

                    Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes(EncryptionKey, new byte[] { 0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76 });
                    encryptor.Key = pdb.GetBytes(32);
                    encryptor.IV = pdb.GetBytes(16);

                    using (CryptoStream cs = new CryptoStream(fsOutput, encryptor.CreateEncryptor(), CryptoStreamMode.Write))
                    {
                        try
                        {

                            while (bytesRead != 0)
                            {
                                bytesRead = fsInput.Read(buffer, 0, bufferLen);
                                sumBytesRead += bytesRead;

                                if (sumBytesRead <= limitBytes) //limit encryption
                                {                                  

                                    if (bytesRead < bufferLen)
                                    {                                                   

                                        cs.Write(buffer, 0, bytesRead);
                                        encryptedByteCounter += bytesRead;
                                        byteWriteCounter += bytesRead;

                                        intBytes = Encoding.Default.GetBytes(encryptedByteCounter.ToString("D7"));

                                        fsOutput.Position = 0;
                                        fsOutput.Write(FILE_HEADER, 0, FILE_HEADER.Length); //we write our header to file, to know which is encrypted
                                        fsOutput.Write(intBytes, 0, intBytes.Length); //we write number of encrypted bytes next to header, for decryption to know
                                        bytesRead = 0;
                                    }
                                    else
                                    {
                                        cs.Write(buffer, 0, bytesRead);
                                        encryptedByteCounter += bytesRead;
                                        byteWriteCounter += bytesRead;

                                    }
                                }
                                else //if the file is bigger than limit, we continue to write normal data (unencrypted)
                                {
                                    if (bytesRead < bufferLen)
                                    {
                                        fsOutput.Write(buffer, 0, bytesRead);
                                        byteWriteCounter += bytesRead;
                                        intBytes = Encoding.Default.GetBytes(encryptedByteCounter.ToString("D7"));

                                        fsOutput.Position = 0;
                                        fsOutput.Write(FILE_HEADER, 0, FILE_HEADER.Length);
                                        fsOutput.Write(intBytes, 0, intBytes.Length);
                                        bytesRead = 0;
                                    }
                                    else
                                    {
                                        fsOutput.Write(buffer, 0, bytesRead);
                                        byteWriteCounter += bytesRead;
                                    }
                                }

                            }

                        }
                        catch (SystemException se)
                        {
                            Console.WriteLine("Exception ENC: " + se);
                        }
                    }
                }
            }
            return true;

        }
        else
        {
            //file is already encrypted
            return false;
        }
    }


}
catch (SystemException se)
{

    Console.WriteLine("Main ENC exception: "+se);

    return false;
}

}

... and Decryption function:

public static bool Decrypt(string inputFilePath, string outputfilePath, string EncryptionKey)
{
byte[] blength = null;
blength = new byte[FILE_HEADER.Length];
long byteWriteCounter = 0;
int bufferLen = 4096; 
byte[] buffer = new byte[bufferLen];
int bytesRead = 1;
long decryptedByteCounter = 0;
long sumBytesRead = 0;
byte[] bufferEncBytes = new byte[7];

try
{

    using (FileStream fsInput = new FileStream(inputFilePath, FileMode.Open))
    {

        fsInput.Read(blength, 0, blength.Length);

        if (blength.SequenceEqual(FILE_HEADER))//check if is our encrypted file
        {


            fsInput.Read(bufferEncBytes, 0, bufferEncBytes.Length);

            int numOfDecBytes = Convert.ToInt32(Encoding.Default.GetString(bufferEncBytes)); //get number of encrypted bytes

            using (FileStream fsOutput = new FileStream(outputfilePath, FileMode.Create))
            {                   
                using (Aes encryptor = Aes.Create())
                {
                    Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes(EncryptionKey, new byte[] { 0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76 });
                    encryptor.Key = pdb.GetBytes(32);
                    encryptor.IV = pdb.GetBytes(16);                        

                    using (CryptoStream cs = new CryptoStream(fsOutput, encryptor.CreateDecryptor(), CryptoStreamMode.Write))
                    {
                        try
                        {

                            while (bytesRead != 0)
                            {
                                bytesRead = fsInput.Read(buffer, 0, bufferLen);
                                sumBytesRead += bytesRead;

                                if (sumBytesRead <= numOfDecBytes) //decrypt until limit
                                {

                                    if (bytesRead < bufferLen)
                                    {
                                        cs.Write(buffer, 0, bytesRead);
                                        decryptedByteCounter += bytesRead;
                                        byteWriteCounter += bytesRead;

                                        bytesRead = 0; //we are at the end of file, end everything
                                    }
                                    else
                                    {
                                        cs.Write(buffer, 0, bytesRead);
                                        decryptedByteCounter += bytesRead;
                                        byteWriteCounter += bytesRead;                                         
                                    }
                                }
                                else //if we have decrypted encrypted bytes, continue with rest of the (normal) data
                                {
                                    if (bytesRead < bufferLen)
                                    {
                                        fsOutput.Write(buffer, 0, bytesRead);
                                        byteWriteCounter += bytesRead;

                                        bytesRead = 0;
                                    }
                                    else
                                    {
                                        fsOutput.Write(buffer, 0, bytesRead);
                                        byteWriteCounter += bytesRead;
                                    }
                                }

                            }

                        }
                        catch (SystemException se)
                        {
                            Console.WriteLine("Exception DECR: " + se);
                        }

                    }

                }

            }
            return true;
        }
        else
        {
            //not right file for decryption
            return false;
        }
    }

}
catch (SystemException eks)
{
    Console.WriteLine("Error: " + eks); //here the exception of Invalid Padding is thrown

    return false;
}
}

Upvotes: 0

Views: 2894

Answers (1)

rossum
rossum

Reputation: 15685

When you encrypt with a block cypher, most modes will add padding. That means that the encrypted data will be longer that the original plaintext, because of the extra padding. You need to keep the padding with the encrypted data, otherwise you will get the bad padding error.

You can either make sure that you handle the padding carefully, or switch to CTR mode, which does not use padding, giving a cyphertext the same length as the plaintext.

Using a Stream Cypher, like Rabbit or Salsa20 would have the same effect.

Upvotes: 2

Related Questions