53. CryptoPad

This program could use the techniques used by the preceding solution to save data in an encrypted format. When you wanted to load a file, the program would decrypt it into a temporary file, load that file, and then delete the temporary file. When you wanted to save data, the program would write the data into an unencrypted temporary file, encrypt it, and then delete the temporary file.

That method would work, but using unencrypted temporary files is risky. An attacker might be able to grab the temporary file before the program can delete it. Even worse, if the program happens to crash at the wrong moment, the temporary file might not be deleted.

Another, safer approach is to encrypt data directly between the program and the encrypted file so the decrypted file is never stored on the computer's hard drive.

The CryptoPad example solution uses a RichTextBox to allow you to edit Rich Text. The program is not a full text editor, however, so it does not provide tools that let you indent text, make bulleted and numbered lists, change fonts, and perform other text editing tasks. You can add those tools if you like. The program does, however, allow you to copy and paste formatted code and even images into its RichTextBox control, so you can still test it with complex data.

The RichTextBox control's Rtf property returns the control's contents as a string containing formatting codes. To save its data, the program encrypts that RTF string directly into a file. To load an encrypted file, the program decrypts the file directly into an RTF string and sets the RichTextBox control's Rtf property to the result.

The following method encrypts string data into a file:

// Encrypt a string and save the results in a file.
public static void EncryptIntoFile(this string plaintext,
string password, string cipherFilename)
{
try
{
// Make the encryptor.
ICryptoTransform cryptoTransform = MakeCryptoTransform(
password, true, new AesCryptoServiceProvider());

// Make streams for the input text and output file.
byte[] plainbytes = Encoding.Unicode.GetBytes(plaintext);
using (MemoryStream inputStream = new MemoryStream(plainbytes))
{
using (FileStream outputStream = new FileStream(
cipherFilename, 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)
{
// Read a block of bytes.
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;
}
}

After reading the last few solutions, this code should seem familiar. It uses the MakeCryptoTransform method to make an encryptor, creates an input stream attached to the string to encrypt, makes an output stream attached to the file, and makes a CryptoStream that connects the encryptor to the output stream. The method reads the input and writes into the output in blocks. When it has finished processing the input string, the method flushes the CryptoStream and is done.

The following code shows how the program decrypts an encrypted file into an RTF string:

// Decrypt a file and return the result in a string.
public static string DecryptFromFile(string password,
string cipherFilename)
{
try
{
// Make the decryptor.
ICryptoTransform cryptoTransform = MakeCryptoTransform(
password, false, new AesCryptoServiceProvider());

// Make streams for the input file and output MemoryStream.
using (FileStream inputStream = new FileStream(cipherFilename,
FileMode.Open, FileAccess.Read))
{
using (MemoryStream outputStream = new MemoryStream())
{
// 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)
{
// Read a block of bytes.
int numBytesRead = inputStream.Read(
buffer, 0, readingBlockSize);
if (numBytesRead == 0) break;

// Write the bytes into the CryptoStream.
cryptoStream.Write(buffer, 0, numBytesRead);
}
cryptoStream.FlushFinalBlock();

// Return the string.
byte[] plainbytes = outputStream.ToArray();
string plaintext =
Encoding.Unicode.GetString(plainbytes);
return plaintext;
}
}
}
}
catch (CryptographicException ex)
{
// The password is incorrect.
throw new CryptographicException("Invalid password.", ex);
}
catch
{
// Re-throw.
throw;
}
}

This code is very similar to the preceding method. The only real difference is that this version converts the output MemoryStream into a string and returns it.

The rest of the example solution performs document management tasks such as keeping track of whether the data has been modified so it can warn you if you try to close the program without saving changes. Download the CryptoPad 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.218.40.17