views:

69

answers:

4

Been playing around with encryption and decrypting files in VC# Express 2010.

All the tutorials and documentation I've seen requires two FileSteams in order to encrypt the file. One for reading the unencrypted version, and the other for encrypting. When I actually wrote the code it kept throwing an error telling me it could not open the file because it was opened by another process at the output filestream.

I'm assuming thats because the file is open by the input filestream. So that means I have to specify a different filename? So even after the operation is successful I'll know have the original unencrypted file in the directory and a separate encrypted version? Doesnt that defeat the point? Or am I doing something wrong here? My code is similar to this...

 public string filename = "test.xml";
 using(FileStream input = new FileStream(filename, FileMode.Open, FileAccess.Read))
 using(FileStream output = new FileStram(filename, FileMode.Open, FileAccess.Write))
 using(....all the crypto stream and transform stuf...)
 {
  ...do the encryption....
 }
A: 

Use File.ReadAllBytes. Then those bytes post to your encryptor, must work.

Eugene Cheverda
+3  A: 

You're right but it's not defeating the point. The (streaming) crypto APIs are intended to encrypt from Src to Dst. Think encrypting output while sending/receiving over a network etc. This keeps them simple, as they should be.

You complicate the issue by using the same file for Src and Dst. That is not totally impossible but like Copying a File over itself it needs some extra care.

Consider that in general, encrypting will increase the File size. So it is not safe to Encrypt a file in place. Decrypting might be, but I wouldn't risk it.

What you need is a Temp file and a rename action after completion.

Henk Holterman
This touches on on another problem: your file isn't safe if the attacker has access to your running computer. If you want to encrypt the file, you have to make sure that the unencrypted bytes never touch the hard drive. If you open your super secret business plan in word, all sorts of temp files are going to get written to the drive that you'll never be able to clean up. If you are looking to protect a file, you really need whole drive encryption.
TwentyMiles
+1  A: 

In your example, you can't create a separate filestream for both input and output on the same file, but you can create a handle that will read and write. The FileAccess enum has the flags attribute, so you'd just say var handle = new FileStream(filename, FileAccess.Read | FileAccess.Write); The obvious downside to this is you are going to have data lost if your encryption doesn't complete successfully.

I recommend having a separate file for the output though, atleast that way you won't lose data if your program breaks unexpectedly. If the encryption completes successfully, then delete the original and rename the encrypted file with the original file name.

Mark H
Is this how other file encryption applications work? I've never seen a residual copy of the unencrypted source after an encryption operations. I should be outputting to a temporary file....create an if statement to monitor for operation success, and then if it is successful, THEN delete the original and rename the temporary in order to replace it? This ensures that the data is not lost?
Stev0
This is how most apps worked back in the day. I'm not sure now. Temporary files will usually be set hidden, and may be in a temporary folder on the disk. The same idea is used in filesystem encryption - if you're moving a file to an encrypted filesystem, the original won't be deleted until the move is completed successfully. You must somehow keep the original data until you know the encryption is completed successfully, because it could be something simple like being out of memory, or a full disk which causes your app to fail.
Mark H
If you really need to recycle the existing file, I'd suggest reading it in fixed block sizes (say something like 4096kb - something that will easily fit into memory). If, and only if each block completes successfully, overwrite the original block, but if not, output to a log file the position where the file is encrypted up to, and any potential data to help recover it. (ie, initialization vectors, keys, cause of error).
Mark H
A: 

There is another parameter where you can specify whether to allow another process to read or write to the file

openFile is the file name, a string type.

using (FileStream fileIn = new FileStream(openFile, FileMode.Open, FileAccess.Read, FileShare.Write))
using (FileStream fileOut = new FileStream(openFile, FileMode.Open, FileAccess.Write, FileShare.Open))

This way, you can read and write to the same file.

while (myfileStream.Position < fileLength)
{

    fileIn .Read(buffer, 0, 51200);

    buffer = encrypt(buffer);

    fileOut .Write(buffer, 0, 51200);                   


}

While this is easy and you don't have to write to a temporary file or have to move/rename etc, this can be really dangerous where if the encryption breaks suddenly for some reason, you will lose data! A

Also, the encrypt function is something i implemented. AesCryptoServiceProvider along with CryptoStream can be used :)

Ranhiru Cooray
I think your while condition is broken. But worse, the position of fileOut will start to overtake that of fileIn, and your file will be garbled beyond repair.
Henk Holterman
@Henk: Yes. You are correct. But the problem was in Mobile Devices, if anyone wants to encrypt a 500MB file, creating another 500MB file would be impossible due to resource constraints. I admit that this is dangerous and possibly faulty, but something of this sort has to done for resource constrained devices, right? Is there any other approach ? :)
Ranhiru Cooray
The OQ doesn't mention Mobile, so your extending the problem here. You might be able to solve the situation w/o a tempfile by adding compression to the mix. But that's not guaranteed (it will break if the Src file is not compressable enough, ie already compressed).
Henk Holterman
@Henk: Thanx! :) I will start another question for this matter :)
Ranhiru Cooray