Introduction
The purpose of this article is demonstrate how to build a Windows Forms application that encrypts files through the use of the RijndaelManaged
class, a symmetric algorithm, which is used to encrypt and decrypt data by using its automatically generated Key and IV. Encryption involves the creation of a cipher (an algorithm) that takes data and a generated key as its input. The algorithm will behave in accordance with the length of the key. A symmetric algorithm is one that uses the same key to both decrypt and encrypt the data file. In our case, we will use the RSACryptoServiceProvider
, an asymmetric algorithm, to encrypt and decrypt the key to the data encrypted by RijndaelManaged
. Asymmetric algorithms are best used for smaller amounts of data, such as a key, as asymmetric algorithms have more overhead than symmetric algorithms. Symmetric algorithms have less overhead when generating them. As its name implies, the RijndaelManaged
class is used by the .NET Framework for managed code; as a government encryption standard, this algorithm is also known as Advanced Encryption Standard, or AES. The algorithm RijndaelManaged
works with a key length that ranges between 128 through 256 bits, in 32 bit increments. The term IV stands for Initialization Vector: it is the data that symmetric encryption algorithms use to further obscure the first block of data being encrypted, making unauthorized decrypting more difficult. The IV, then, gets or sets the initialization vector for the symmetric algorithm. Like the Key property, both the encryptor and the decryptor must specify the same value. The Key gets or sets the secret key pair for the symmetric algorithm. After encryption, you must store this value and transfer it to the decryptor. During decryption, you must specify the same key used for encryption. The downloadable solution files were built using Visual Studio 2010, but the code presented in the later section is constructed as one file for the command line.
The first step in this process is to make three folders: c:\docs, c:\Encrypt, and c:\Decrypt. Write out some text files and place them into the C:\docs directory. The Forms application requires six buttons, two labels, and two OpenFileDialog
controls to be dragged and dropped onto the surface of the form. The AutoSize
property of the first label (which goes on the top of the form) should be set to false
. This will give you room to enlarge the font and change the color. This is where is the textual output appears when we click the Create Keys button. So leave the text property for the first label blank. The text for the second label should state: “Secure Your Files”. That label is also has its AutoSize
property set to false
.
The Source Code in One File
Notice the private
methods, Encrypt
and Decrypt
, and the event handlers for the button controls. The Encrypt
button handler invokes a method that is private
to that module, as does the Decrypt
method. Note that there are no user input fields in this application. We are using the OpenFileDialog
controls to access files that are to be encrypted:
using System;
using System.IO;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Security.Cryptography;
using System.Text;
using System.Windows.Forms;
namespace Security
{
public partial class Form1 : Form
{
private System.Windows.Forms.Button buttonEncryptFile;
private System.Windows.Forms.Button buttonDecryptFile;
private System.Windows.Forms.Button buttonCreateAsmKeys;
private System.Windows.Forms.Button buttonExportPublicKey;
private System.Windows.Forms.Button buttonImportPublicKey;
private System.Windows.Forms.Button buttonGetPrivateKey;
private System.Windows.Forms.OpenFileDialog openFileDialog1;
private System.Windows.Forms.OpenFileDialog openFileDialog2;
private System.Windows.Forms.Label label1;
private System.Windows.Forms.PictureBox pictureBox1;
private System.Windows.Forms.Label label2;
public Form1()
{
InitializeComponent();
}
CspParameters cspp = new CspParameters();
RSACryptoServiceProvider rsa;
const string EncrFolder = @"c:\Encrypt\";
const string DecrFolder = @"c:\Decrypt\";
const string SrcFolder = @"c:\docs\";
const string PubKeyFile = @"c:\encrypt\rsaPublicKey.txt";
const string keyName = "Key01";
private void InitializeComponent()
{
this.buttonEncryptFile = new System.Windows.Forms.Button();
this.buttonDecryptFile = new System.Windows.Forms.Button();
this.buttonCreateAsmKeys = new System.Windows.Forms.Button();
this.buttonExportPublicKey = new System.Windows.Forms.Button();
this.buttonImportPublicKey = new System.Windows.Forms.Button();
this.buttonGetPrivateKey = new System.Windows.Forms.Button();
this.openFileDialog1 = new System.Windows.Forms.OpenFileDialog();
this.openFileDialog2 = new System.Windows.Forms.OpenFileDialog();
this.label1 = new System.Windows.Forms.Label();
this.pictureBox1 = new System.Windows.Forms.PictureBox();
this.label2 = new System.Windows.Forms.Label();
((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit();
this.SuspendLayout();
this.buttonEncryptFile.Location = new System.Drawing.Point(484, 44);
this.buttonEncryptFile.Name = "buttonEncryptFile";
this.buttonEncryptFile.Size = new System.Drawing.Size(125, 23);
this.buttonEncryptFile.TabIndex = 0;
this.buttonEncryptFile.Text = "Encrypt File";
this.buttonEncryptFile.UseVisualStyleBackColor = true;
this.buttonEncryptFile.Click +=
new System.EventHandler(this.buttonEncryptFile_Click);
this.buttonDecryptFile.Location = new System.Drawing.Point(484, 95);
this.buttonDecryptFile.Name = "buttonDecryptFile";
this.buttonDecryptFile.Size = new System.Drawing.Size(125, 23);
this.buttonDecryptFile.TabIndex = 1;
this.buttonDecryptFile.Text = "Decrypt File";
this.buttonDecryptFile.UseVisualStyleBackColor = true;
this.buttonDecryptFile.Click +=
new System.EventHandler(this.buttonDecryptFile_Click);
this.buttonCreateAsmKeys.Location = new System.Drawing.Point(484, 145);
this.buttonCreateAsmKeys.Name = "buttonCreateAsmKeys";
this.buttonCreateAsmKeys.Size = new System.Drawing.Size(125, 23);
this.buttonCreateAsmKeys.TabIndex = 2;
this.buttonCreateAsmKeys.Text = "Create Keys";
this.buttonCreateAsmKeys.UseVisualStyleBackColor = true;
this.buttonCreateAsmKeys.Click +=
new System.EventHandler(this.buttonCreateAsmKeys_Click);
this.buttonExportPublicKey.Location = new System.Drawing.Point(484, 207);
this.buttonExportPublicKey.Name = "buttonExportPublicKey";
this.buttonExportPublicKey.Size = new System.Drawing.Size(125, 23);
this.buttonExportPublicKey.TabIndex = 3;
this.buttonExportPublicKey.Text = "Export Public Key";
this.buttonExportPublicKey.UseVisualStyleBackColor = true;
this.buttonExportPublicKey.Click +=
new System.EventHandler(this.buttonExportPublicKey_Click);
this.buttonImportPublicKey.Location = new System.Drawing.Point(484, 271);
this.buttonImportPublicKey.Name = "buttonImportPublicKey";
this.buttonImportPublicKey.Size = new System.Drawing.Size(125, 23);
this.buttonImportPublicKey.TabIndex = 4;
this.buttonImportPublicKey.Text = "Import Public Key";
this.buttonImportPublicKey.UseVisualStyleBackColor = true;
this.buttonImportPublicKey.Click +=
new System.EventHandler(this.buttonImportPublicKey_Click);
this.buttonGetPrivateKey.Location = new System.Drawing.Point(484, 330);
this.buttonGetPrivateKey.Name = "buttonGetPrivateKey";
this.buttonGetPrivateKey.Size = new System.Drawing.Size(125, 23);
this.buttonGetPrivateKey.TabIndex = 5;
this.buttonGetPrivateKey.Text = "Get Private Key";
this.buttonGetPrivateKey.UseVisualStyleBackColor = true;
this.buttonGetPrivateKey.Click +=
new System.EventHandler(this.buttonGetPrivateKey_Click);
this.openFileDialog1.FileName = "openFileDialog1";
this.openFileDialog2.FileName = "openFileDialog2";
this.label1.BackColor = System.Drawing.Color.Red;
this.label1.Font = new System.Drawing.Font
("Times New Roman", 21.75F, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.label1.Location = new System.Drawing.Point(46, 23);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(262, 44);
this.label1.TabIndex = 6;
this.pictureBox1.Location = new System.Drawing.Point(101, 135);
this.pictureBox1.Name = "pictureBox1";
this.pictureBox1.Size = new System.Drawing.Size(165, 205);
this.pictureBox1.TabIndex = 7;
this.pictureBox1.TabStop = false;
this.label2.Font = new System.Drawing.Font
("Times New Roman", 18F, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.label2.Location = new System.Drawing.Point(52, 95);
this.label2.Name = "label2";
this.label2.Size = new System.Drawing.Size(214, 37);
this.label2.TabIndex = 8;
this.label2.Text = "Secure Your Files";
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.BackColor = System.Drawing.Color.Cyan;
this.ClientSize = new System.Drawing.Size(631, 395);
this.Controls.Add(this.label2);
this.Controls.Add(this.pictureBox1);
this.Controls.Add(this.label1);
this.Controls.Add(this.buttonGetPrivateKey);
this.Controls.Add(this.buttonImportPublicKey);
this.Controls.Add(this.buttonExportPublicKey);
this.Controls.Add(this.buttonCreateAsmKeys);
this.Controls.Add(this.buttonDecryptFile);
this.Controls.Add(this.buttonEncryptFile);
this.Name = "Form1";
this.Text = "Form1";
((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit();
this.ResumeLayout(false);
}
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
private void buttonCreateAsmKeys_Click(object sender, EventArgs e)
{
cspp.KeyContainerName = keyName;
rsa = new RSACryptoServiceProvider(cspp);
rsa.PersistKeyInCsp = true;
if (rsa.PublicOnly == true)
label1.Text = "Key: " + cspp.KeyContainerName + " - Public Only";
else
label1.Text = "Key: " + cspp.KeyContainerName + " - Full Key Pair";
}
private void buttonEncryptFile_Click(object sender, EventArgs e)
{
if (rsa == null)
MessageBox.Show("Key not set.");
else
{
openFileDialog1.InitialDirectory = SrcFolder;
if (openFileDialog1.ShowDialog() == DialogResult.OK)
{
string fName = openFileDialog1.FileName;
if (fName != null)
{
FileInfo fInfo = new FileInfo(fName);
string name = fInfo.FullName;
EncryptFile(name);
}
}
}
}
private void EncryptFile(string inFile)
{
RijndaelManaged rjndl = new RijndaelManaged();
rjndl.KeySize = 256;
rjndl.BlockSize = 256;
rjndl.Mode = CipherMode.CBC;
ICryptoTransform transform = rjndl.CreateEncryptor();
byte[] keyEncrypted = rsa.Encrypt(rjndl.Key, false);
byte[] LenK = new byte[4];
byte[] LenIV = new byte[4];
int lKey = keyEncrypted.Length;
LenK = BitConverter.GetBytes(lKey);
int lIV = rjndl.IV.Length;
LenIV = BitConverter.GetBytes(lIV);
int startFileName = inFile.LastIndexOf("\\") + 1;
string outFile = EncrFolder + inFile.Substring
(startFileName, inFile.LastIndexOf(".") - startFileName) + ".enc";
using (FileStream outFs = new FileStream(outFile, FileMode.Create))
{
outFs.Write(LenK, 0, 4);
outFs.Write(LenIV, 0, 4);
outFs.Write(keyEncrypted, 0, lKey);
outFs.Write(rjndl.IV, 0, lIV);
using (CryptoStream outStreamEncrypted =
new CryptoStream(outFs, transform, CryptoStreamMode.Write))
{
int count = 0;
int offset = 0;
int blockSizeBytes = rjndl.BlockSize / 8;
byte[] data = new byte[blockSizeBytes];
int bytesRead = 0;
using (FileStream inFs = new FileStream(inFile, FileMode.Open))
{
do
{
count = inFs.Read(data, 0, blockSizeBytes);
offset += count;
outStreamEncrypted.Write(data, 0, count);
bytesRead += blockSizeBytes;
}
while (count > 0);
inFs.Close();
}
outStreamEncrypted.FlushFinalBlock();
outStreamEncrypted.Close();
}
outFs.Close();
}
}
private void buttonDecryptFile_Click(object sender, EventArgs e)
{
if (rsa == null)
MessageBox.Show("Key not set.");
else
{
openFileDialog2.InitialDirectory = EncrFolder;
if (openFileDialog2.ShowDialog() == DialogResult.OK)
{
string fName = openFileDialog2.FileName;
if (fName != null)
{
FileInfo fi = new FileInfo(fName);
string name = fi.Name;
DecryptFile(name);
}
}
}
}
private void DecryptFile(string inFile)
{
RijndaelManaged rjndl = new RijndaelManaged();
rjndl.KeySize = 256;
rjndl.BlockSize = 256;
rjndl.Mode = CipherMode.CBC;
byte[] LenK = new byte[4];
byte[] LenIV = new byte[4];
string outFile = DecrFolder + inFile.Substring
(0, inFile.LastIndexOf(".")) + ".txt";
using (FileStream inFs = new FileStream(EncrFolder + inFile, FileMode.Open))
{
inFs.Seek(0, SeekOrigin.Begin);
inFs.Seek(0, SeekOrigin.Begin);
inFs.Read(LenK, 0, 3);
inFs.Seek(4, SeekOrigin.Begin);
inFs.Read(LenIV, 0, 3);
int lenK = BitConverter.ToInt32(LenK, 0);
int lenIV = BitConverter.ToInt32(LenIV, 0);
int startC = lenK + lenIV + 8;
int lenC = (int)inFs.Length - startC;
byte[] KeyEncrypted = new byte[lenK];
byte[] IV = new byte[lenIV];
inFs.Seek(8, SeekOrigin.Begin);
inFs.Read(KeyEncrypted, 0, lenK);
inFs.Seek(8 + lenK, SeekOrigin.Begin);
inFs.Read(IV, 0, lenIV);
Directory.CreateDirectory(DecrFolder);
byte[] KeyDecrypted = rsa.Decrypt(KeyEncrypted, false);
ICryptoTransform transform = rjndl.CreateDecryptor(KeyDecrypted, IV)
using (FileStream outFs = new FileStream(outFile, FileMode.Create))
{
int count = 0;
int offset = 0;
int blockSizeBytes = rjndl.BlockSize / 8;
byte[] data = new byte[blockSizeBytes];
inFs.Seek(startC, SeekOrigin.Begin);
using (CryptoStream outStreamDecrypted =
new CryptoStream(outFs, transform, CryptoStreamMode.Write))
{
do
{
count = inFs.Read(data, 0, blockSizeBytes);
offset += count;
outStreamDecrypted.Write(data, 0, count);
}
while (count > 0);
outStreamDecrypted.FlushFinalBlock();
outStreamDecrypted.Close();
}
outFs.Close();
}
inFs.Close();
}
}
private void buttonExportPublicKey_Click(object sender, EventArgs e)
{
Directory.CreateDirectory(EncrFolder);
StreamWriter sw = new StreamWriter(PubKeyFile, false);
sw.Write(rsa.ToXmlString(false));
sw.Close();
}
private void buttonImportPublicKey_Click(object sender, EventArgs e)
{
StreamReader sr = new StreamReader(PubKeyFile);
cspp.KeyContainerName = keyName;
rsa = new RSACryptoServiceProvider(cspp);
string keytxt = sr.ReadToEnd();
rsa.FromXmlString(keytxt);
rsa.PersistKeyInCsp = true;
if (rsa.PublicOnly == true)
label1.Text = "Key: " + cspp.KeyContainerName + " - Public Only";
else
label1.Text = "Key: " + cspp.KeyContainerName + " - Full Key Pair";
sr.Close();
}
private void buttonGetPrivateKey_Click(object sender, EventArgs e)
{
cspp.KeyContainerName = keyName;
rsa = new RSACryptoServiceProvider(cspp);
rsa.PersistKeyInCsp = true;
if (rsa.PublicOnly == true)
label1.Text = "Key: " + cspp.KeyContainerName + " - Public Only";
else
label1.Text = "Key: " + cspp.KeyContainerName + " - Full Key Pair";
}
}
}
It is always good practice to build the forms application, examine the object browser, and set the properties of the classes that are, in this case, controls. This file was built, however, on the command line prompt of the .NET Framework. Here is how it looks before it is used:
To Create Keys, Encrypt, and Decrypt
- Click the Create Keys button. The label displays the key name and shows that it is a full key pair.
- Click the Export Public Key button. Note that exporting the public key parameters does not change the current key.
- Click the Encrypt File button and select a file.
- Click the Decrypt Filebutton and select the file just encrypted.
- Examine the file just decrypted.
- Close the application and restart it to test retrieving persisted key containers in the next scenario.
To Encrypt using the Public Key
- Click the Import Public Key button. The label displays the key name and shows that it is public only.
- Click the Encrypt File button and select a file.
- Click the Decrypt Filebutton and select the file just encrypted. This will fail because you must have the private key to decrypt.
This scenario demonstrates having only the public key to encrypt a file for another person. Typically, that person would give you only the public key and withhold the private key for decryption.
To Decrypt using the Private Key
- Click the Get Private Key button. The label displays the key name and shows whether it is the full key pair.
- Click the Decrypt File button and select the file just encrypted. This will be successful because you have the full key pair to decrypt.
References
History
- 23rd April, 2010: Initial post