This walkthrough provides code examples for encrypting and decrypting content. These code examples are designed for Windows forms applications. This application does not demonstrate real-world scenarios, such as using smart cards, but rather demonstrates the basics of encryption and decryption.
This walkthrough uses the following Cryptographic guidelines:
Use the RijndaelManaged class (a symmetric algorithm) and encrypt and decrypt the data using its automatically generated keys and IV.
Use RSACryptoServiceProvider (an asymmetric algorithm) to encrypt and decrypt keys for rijndaelmanaged encrypted data. Asymmetric algorithms are best suited for small amounts of data, such as keys.
Attention |
If your goal is to protect data on your computer, instead of exchanging encrypted content with others, consider using the ProtectedData or Protectedmemory class. |
The following table summarizes the cryptographic tasks in this topic.
Task |
Description |
Create a Windows Forms application |
Lists the controls that are required to run the application. |
Declaring global objects |
Declare string path variables, CspParameters, and RSACryptoServiceProvider to get the global context of the Form class. |
Creating an asymmetric key |
Creates an asymmetric public/private key value pair and assigns it a key container name. |
Encrypting files |
Displays a dialog box to select the file to encrypt and encrypt the file. |
Decrypt files |
Displays a dialog box to select the encrypted file to decrypt and decrypt the file. |
Get private key |
Gets the full key pair that uses the key container name. |
Export Public key |
Save the key with only public parameters into an XML file. |
Import Public key |
Loads the key from an XML file into the key container. |
Test the application |
Lists the procedures used to test this application. |
This application needs to reference the following namespaces:
Create a Windows forms application
Most code samples are designed as event handlers for button controls. The following table lists the controls that are required by the sample application and the names that are required for these controls to match the code sample:
Control |
name |
Text properties (as needed) |
Button |
Buttonencryptfile |
Encrypting files |
Button |
Buttondecryptfile |
Decrypt files |
Button |
Buttoncreateasmkeys |
Create key |
Button |
Buttonexportpublickey |
Export Public key |
Button |
Buttonimportpublickey |
Import Public key |
Button |
Buttongetprivatekey |
Get private key |
Label |
Label1 |
|
OpenFileDialog |
OpenFileDialog1 |
|
OpenFileDialog |
OpenFileDialog2 |
|
Double-click the button in the Visual Studio designer to create an event handler for the button.
declaring global Objects
Add the following code example to the form's constructor. Edit the string variables that represent your environment and preferences.
C#vb
Declare cspparmeters and rsacryptoserviceprovider//objects with global scope of your Form class. CspParameters CSPP = new CspParameters (); RSACryptoServiceProvider rsa;//Path Variables for source, encryption, and//decryption folders. Must end with a backslash.const string encrfolder = @ "c:\Encrypt\"; const string decrfolder = @ "c:\Decrypt\"; const string S Rcfolder = @ "c:\docs\";//Public key Fileconst String pubkeyfile = @ "C:\encrypt\rsaPublicKey.txt";//Key container name fo r//private/public Key value pair.const string keyName = "Key01";
creating an asymmetric key
This task creates an asymmetric key that is used to encrypt and decrypt the rijndaelmanaged key (for encrypted content) and displays the key container name on the label control.
Add the following code example as a click event handler for the Create Key button:buttoncreateasmkeys_click.
C#vb
private void Buttoncreateasmkeys_click (object sender, System.EventArgs e) { //Stores a key pair in the key container.< C1/>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";}
Encrypting Files
This task involves two methods: the "Encrypt file" button's event handler method buttonEncryptFile_Click and the encryptfile method. The first method displays a dialog box to select a file and pass the corresponding file name to the second method, which performs the cryptographic operation.
Save the encrypted content, keys, and IV to a FileStream called an encrypted package.
The EncryptFile method performs the following actions:
Create a rijndaelmanaged symmetric algorithm to encrypt the content.
Create an RSACryptoServiceProvider instance to encrypt the rijndaelmanaged key.
Use CryptoStream to read the FileStream of the source file to the target FileStream of the encrypted file and encrypt (in bytes).
A byte array that determines the length of the encryption key and IV and creates its length value.
Writes the key, IV, and its length value to the encryption package.
The format of the encryption package is as follows:
Key length, Byte 0-3
IV length, Byte 4-7
Encryption key
IV
Password text
By obtaining the length of the key and IV, you can determine the starting point and length of all parts of the encrypted package in order to encrypt the file.
Add the following code example as a click event handler for the Encrypt Files button:buttonencryptfile_click.
C#vb
private void buttonEncryptFile_Click (object sender, System.EventArgs e) { if (RSA = = null) MessageBox.Show ("Key Not set. "); else { //Display A dialog box to select a file to encrypt. Openfiledialog1.initialdirectory = Srcfolder; if (openfiledialog1.showdialog () = = DialogResult.OK) { string fName = Openfiledialog1.filename; if (fName! = null) { FileInfo finfo = new FileInfo (fName); Pass the file name without the path. String name = Finfo.name; EncryptFile (name);}}}
Add the following EncryptFile method to the form.
C#vb
private void EncryptFile (string inFile) {//Create instance of Rijndael for//Symetric encryption of the data. RijndaelManaged Rjndl = new RijndaelManaged (); Rjndl. KeySize = 256; Rjndl. BlockSize = 256; Rjndl. Mode = CIPHERMODE.CBC; ICryptoTransform transform = Rjndl. CreateEncryptor (); Use RSACryptoServiceProvider to//Enrypt the Rijndael key. byte[] keyencrypted = RSA. Encrypt (Rjndl. Key, false); Create byte arrays to contain//the length values of the key and Iv. 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); Write the following to the FileStream//for the encrypted file (OUTFS)://-Length of the key//-Length of The IV//-ecrypted key//-the IV//-The encrypted cipher content//change of the file ' s extension to '. Enc "String outFile = Encrfolder + InFIle. Substring (0, Infile.lastindexof (".")) + ". 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); Now write the cipher text using//a CryptoStream for encrypting. using (CryptoStream outstreamencrypted = new CryptoStream (Outfs, Transform, CryptoStreamMode.Write)) { By encrypting a chunk at//a time, you can save memory//and accommodate large F Iles. int count = 0; int offset = 0; Blocksizebytes can is any arbitrary size. 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 (); }}
Decrypt Files
This task involves two methods: the event handler method of the Decrypt File button buttonEncryptFile_Click and the decryptfile method. The first method displays a dialog box to select a file and pass the corresponding file name to the second method, which performs the decryption operation.
The Decrypt method performs the following actions:
Creates a rijndaelmanaged symmetric algorithm to decrypt the content.
Reads the first 8 bytes of the cryptographic packet's FileStream into a byte array to obtain the length of the encryption key and IV.
Extracts the keys and IV from the cryptographic package into a byte array.
Creates an RSACryptoServiceProvider instance to decrypt the rijndaelmanaged key.
Use CryptoStream to read the cipher text portion of the FileStream encryption package into the FileStream of the decrypted file and decrypt it in bytes. When this is done, decryption is complete.
Add the following code example as a click event handler for the Decrypt File button.
C#vb
private void Buttondecryptfile_click (object sender, EventArgs e) { if (RSA = = null) MessageBox.Show ("Key not set.") ); else { //Display A dialog box to select the encrypted file. 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);}}}
Add the following DecryptFile method to the form.
C#vb
private void DecryptFile (string inFile) {//Create instance of Rijndael for//Symetric decryption of the data. RijndaelManaged Rjndl = new RijndaelManaged (); Rjndl. KeySize = 256; Rjndl. BlockSize = 256; Rjndl. Mode = CIPHERMODE.CBC; Rjndl. Padding = Paddingmode.none; Create byte arrays to get the length of//The encrypted key and Iv. These values were stored as 4 bytes per//At the beginning of the encrypted package. byte[] LenK = new Byte[4]; byte[] Leniv = new Byte[4]; Consruct the file name for the decrypted file. String outFile = Decrfolder + infile.substring (0, Infile.lastindexof (".")) + ". txt"; Use FileStream objects to read the encrypted//file (INFs) and save the decrypted file (OUTFS). 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); Convert the lengths to integer values. int LenK = Bitconverter.toint32 (LenK, 0); int leniv = Bitconverter.toint32 (leniv, 0); Determine the start postition of//The Ciphter text (STARTC)//and its length (LENC). int STARTC = LenK + Leniv + 8; int lenc = (int) INFS.LENGTH-STARTC; Create the byte arrays for//The encrypted Rijndael key,//The IV, and the cipher text. byte[] keyencrypted = new Byte[lenk]; byte[] IV = new Byte[leniv]; Extract the key and IV//starting from index 8//after the length values. Infs.seek (8, Seekorigin.begin); Infs.read (keyencrypted, 0, LenK); Infs.seek (8 + LenK, seekorigin.begin); Infs.read (IV, 0, Leniv); Use RSACryptoServiceProvider//To decrypt the Rijndael key. byte[] keydecrypted = RSA. Decrypt (keyencrypted, false); Decrypt the key. ICryptoTransform transform = Rjndl. CreateDecryptor (keydecrypted, IV); Decrypt the cipher text from//from the Filesteam of the encrypted//file (INFs) into the FileStream For the decrypted file (OUTFS). using (FileStream Outfs = new FileStream (OutFile, FileMode.Create)) {int count = 0; int offset = 0; Blocksizebytes can is any arbitrary size. int blocksizebytes = Rjndl. BLOCKSIZE/8; byte[] data = new Byte[blocksizebytes]; By decrypting a chunk a time,//You can save memory and//accommodate large files. Start at the beginning//of the cipher text. 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 (); }}
Export Public Key
This task saves the key created by the Create Key button to a file that exports only public parameters.
This task simulates a situation in which little Red provides her public key to Xiaoming so that the latter can encrypt the file sent to her. Xiaoming and other people with the public key will not be able to decrypt these files because they do not have a full key pair with private parameters.
Add the following code example as a click event handler for the Create Key button:buttonexportpublickey_click.
C#vb
void Buttonexportpublickey_click (object sender, System.EventArgs e) { //Save The public key created by the RSA // to a file. Caution, persisting the //key to a file is a security risk. StreamWriter SW = new StreamWriter (pubkeyfile); Sw. Write (RSA. Toxmlstring (false)); Sw. Close ();}
Import Public Key
This task loads the key created by the Export Public key button (with public parameters only) and sets it as the key container name.
This task simulates a situation in which xiaoming will load a key with only public parameters provided by little red so that he can encrypt the file sent to the red.
Add the following code example as a click event handler for the Import Public key button:buttonimportpublickey_click.
C#vb
void Buttonimportpublickey_click (object sender, System.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 ();}
Get private key
This task sets the key container name to the name of the key created using the Create Key button. The key container will contain a full key pair with private parameters.
This task simulates a situation in which small red uses its own private key to decrypt files encrypted by Xiaoming.
Add the following code example as a click event handler for the Get Private key button:buttongetprivatekey_click.
C#vb
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";}
Test the application
After the application is built, perform the following test scenarios.
Creating keys, encryption, and decryption
Click the Create Key button. The label displays the key name and shows that the key is a full key pair.
Click the Export Public Key button. Note that exporting the public key parameter does not change the current key.
Click the Encrypt File button and select a file.
Click the Decrypt File button and select the file you just encrypted.
Check the file you just decrypted.
Close and restart the application to test the retrieval of a reserved key container in the next scenario.
Encrypt with public key
Click the Import Public Key button. The label displays the key name and shows that the key is only public.
Click the Encrypt File button and select a file.
Click the Decrypt File button and select the file you just encrypted. This operation will fail because you must have a private key to decrypt it.
This scenario demonstrates how to encrypt files that are sent to other people using only the public key. Typically, this person will only provide you with the public key, while the private key used for decryption is reserved.
Decrypting using the private key
Click the Get Private Key button. The label displays the key name and displays whether the key is a full key pair.
Click the Decrypt File button and select the file you just encrypted. This operation succeeds because you have a full key pair for decryption.
Create a cryptographic application