52. Encrypt and decrypt files

You could adapt the techniques for encrypting strings from the preceding solution to encrypt files. You would simply use File.ReadAllBytes to read a file into a byte array, call the EncryptDecryptBytes method to encrypt or decrypt the bytes, and then use File.WriteAllBytes to save the results into the output file.

That method would work reasonably well for small files, but holding the file's bytes in memory could be a problem for very large files. Fortunately, there's a better approach.

The encryption methods read and write data through streams. If you use the same setup methods used by the preceding solution, then you can use file streams to easily encrypt and decrypt files. The following code shows the CryptFile method that encrypts or decrypts files:

// Encrypt or decrypt a file into another file.
private static void CryptFile(string password, string inputFilename,
string outputFilename, bool doEncryption)
{
try
{
// Make the encryptor or decryptor.
ICryptoTransform cryptoTransform = MakeCryptoTransform(
password, doEncryption, new AesCryptoServiceProvider());

// Make streams for the input and output files.
using (FileStream inputStream = new FileStream(inputFilename,
FileMode.Open, FileAccess.Read))
{
using (FileStream outputStream = new FileStream(
outputFilename, FileMode.Create, FileAccess.Write))
{
// Attach a CryptoStream.
using (CryptoStream cryptoStream = new CryptoStream(
outputStream, cryptoTransform,
CryptoStreamMode.Write))
{
// Read and write in blocks.
const int readingBlockSize = 16 * 1024;
byte[] buffer = new byte[readingBlockSize];
while (true)
{
int numBytesRead = inputStream.Read(
buffer, 0, readingBlockSize);
if (numBytesRead == 0) break;

// Write the bytes into the CryptoStream.
cryptoStream.Write(buffer, 0, numBytesRead);
}
cryptoStream.FlushFinalBlock();
}
}
}
}
catch (CryptographicException ex)
{
// The password is incorrect.
throw new CryptographicException("Invalid password.", ex);
}
catch
{
// Re-throw.
throw;
}
}

The method encloses all of its code in a try…catch block in case it is trying to decrypt a file with the wrong password. Inside the block, the code uses the MakeCryptoTransform method used by the preceding solution to prepare a cryptographic transform.

Next, the code creates an input file stream to read the input file and an output file stream to write the output file. It then makes a CryptoStream object that attaches the cryptographic transform to the output stream.

The method then enters a loop that processes the input file in blocks. Each time through the loop, the code reads a block. If the read returns no bytes, then the program has finished reading the input file so it breaks out of its loop. If the read returns some bytes, the method writes those bytes into the CryptoStream, which automatically encrypts or decrypts the bytes and writes the results into the output stream. After the loop ends, the code calls the CryptoStream object's FlushFinalBlock method to flush any pending data into the output stream.

The following two methods use the CryptFile method to encrypt and decrypt files:

// Encrypt a file into another file.
public static void EncryptFile(string password,
string plainFilename, string cipherFilename)
{
CryptFile(password, plainFilename, cipherFilename, true);
}

// Decrypt a file into another file.
public static void DecryptFile(string password,
string cipherFilename, string plainFilename)
{
CryptFile(password, cipherFilename, plainFilename, false);
}

These methods simply call CryptFile, passing it the appropriate parameters.

The rest of the example solution's code allows you to open a file, encrypt it into a new file, and decrypt an encrypted file. It also displays the original, encrypted, and recovered files. Download the EncryptDecryptFiles example solution to see additional details.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.223.0.133