views:

110

answers:

2

I have created a test (not real) encryption function which takes a byte[] and replaces all the bytes with 0xff and returns

private byte[] encrypt(byte[] input)
        {


            for (int i = 0; i < input.Length; i++)
            {
                input[i] = 0xff;
            }

            return input;



        }

Now i want to try this test encryption procedure on a file. But i want to be able to read and write to the SAME file.

This is what I have done so far

using (FileStream myfileStream = new FileStream(openFile, FileMode.Open,FileAccess.ReadWrite))

    {   

    byte[] buffer = new byte[16]; 



        while (myfileStream.Position < myfileStream.Length)
        {

          myfileStream.Read(buffer, 0, 16);

          buffer = encrypt(buffer);

          myfileStream.Position -= 16;

          myfileStream.Write(buffer, 0, 16);

         }

         myfileStream.Close();            

    }

This works fine but I know I am not doing this right. This seems to have VERY serious performance issues where it took 24 seconds for a 1 MB file. (Tested with a StopWatch in a WinMo 6 Pro emulator).

What am I doing wrong here? What can I do to increase the performance when reading and writing to/from the same file at the same time ? Please advise. Thanx a lot in advance :)


UPDATE:

I reduced the time it took significantly (from 24 seconds, down to 6 seconds) by using 2 FileStream objects pointing to the same file with FileShare.ReadWrite property.

Is this safe to do? Is this ok?

UPDATE AGAIN

Although I have used a fake encryption algorithm, I am hoping to use AES with CBC + CTS.

+3  A: 

A couple of things come to mind immediately:

  1. Use a larger buffer - why only 16 bytes?
  2. Don't write to the same file - you can delete/rename after encrypting.

Update

Even with EAS and the 16 byte constraint, you can do the encryption in memory (for large files, use a large buffer instead of encrypting the whole file in memory).

You should not be using two filesteams like that - you may end up writing parts of the file that you will be reading on later.

In regards to the buffers - you can read large chunks from disk, then operate on 16 bytes at a time in memory before writing back large chunks of encrypted data.

Oded
Indeed, a small buffer means a lot more OS calls to read from the physical drive, hence a major performance hit!
Noldorin
I used 16 bytes because the AES-128 works on 16 bytes at a time. Will it be better if i read more than 16 bytes and perform the AES encryption in memory and write it back?
Ranhiru Cooray
@Ranhiru: I could sware the `System.Security.Cryptography` classes for AES-128 allow you to take a `Stream` as input... that's the obvious solution.
Noldorin
@Noldorin: Yes. But due to some unfortunate reason I cannot use the System.Security.Cryptography namespace. I know it is very bad, but the AES algorithm was written by me.
Ranhiru Cooray
I see. What's the problem with the in-built classes, I'm curious?
Noldorin
Of course there is absolutely nothing wrong in the built in classes. But the problem is my lecturer :P He keeps on insisting that i write the algorithm my self :) Anyway the algorithm is done writing and works :) BUT, I have seen in numerous occasions that RijndaelManaged performs very badly compared to DESCryptoServiceProvider and TripleDESCryptoServiceProvider. And unfortunately the .NET CF does not have a AESCryptoServiceProvider :(
Ranhiru Cooray
@Oded: So i should use MemoryStream object?
Ranhiru Cooray
@Ranhiru - that will certainly help.
Oded
@Oded: Creating a new file would be very costly due to storage constraints in mobile devices :(
Ranhiru Cooray
+2  A: 

Do not check the file length in the while block (i.e. myfileStream.Length), as this results in a system call to check the file length on each iteration. Instead put the file length in a variable before the while loop, and use the variable instead.

Whilst a larger buffer will help, remember that some buffering will already be taken care of by:

  1. The stream class itself.
  2. The operating system disk cache.
  3. The drive buffer.

Reading the file length repeatedly in the while block is likely to be the major problem.

chibacity
Might account for some of the slowness, but not the majority I suspect... worth doing a profiling on this.
Noldorin
@Noldorin I have seen this problem many times.
chibacity
It's possible, yeah. Not sure on the cases when the compiler optimises such stuff away though.
Noldorin
Writing `Position` to seek the `FileStream` pretty much disables any write caching that could be going on within `FileStream`.
Ben Voigt
@Noldorin The compiler does not optimize this away. It is not an array bounds check, which would be fixed sized. This is a stream whose length could change. Not a case the compiler can optimize clearly.
chibacity
@Ben: Very good point. Would it not prevent read caching too to some degree?
Noldorin
Thanx! I shaved off nearly 2 seconds from saving the length to a variable and using it in the while loop :)
Ranhiru Cooray
@Ben Checking the length of a file also affects the OS disk cache. I use this technique myself in unit testing to force the OS to flush changes to disk.
chibacity