Return to HomePage



Encrypt a file via a block cipher using AES (VB.NET)



Applies To

* .NET Framework 2.0
* VB.NET

Summary

The purpose of this code is to demonstrate the proper use of a symmetric block cipher. This test case utilizes AES (Rijndael) which serves as the current NIST encryption standard.


Objectives

* To provide confidentiality of files which are transmitted over insecure or untrusted communication channels.
* To provide confidentiality of files in storage until they are needed by a user or application

Scenarios

* Application developer desires confidentiality for files in storage or in transit.


Solution Example



		        Private  Sub [EncryptFile(ByVal] [sInputFilename] As String, [ByVal] [sOutputFilename] As String, [ByVal] sKey As String, [ByVal] sIV As String)
		            ' The default AES key size under the .NET framework is 256.  The following
		            ' call will create an AES crypto provider and create a random initialization
		            ' vector and key. The crypto mode defaults to CBC ensuring the proper chaining 
		            ' of data to mitigate repetition of cipher text blocks.
	

		            Dim rijndaelAlg As Rijndael =  Rijndael.Create() 
	

		            ' One could override the default randomly generated key and initialization vector
		            ' by setting the following properties to the Rijndael Crypto Provider, e.g.:
		            '
		            '  rijndaelAlg.Key = some_key_val;
		            '  rijndaelAlg.IV = some_iv_val;
		            '  [rijndaelAlg.KeySize] = 256; // other valid key sizes: 128 or 192 (defaults to 256)
		            ' 
		            ' Similarly a developer may wish to change the default encryption mode, e.g.:
		            '
		            '  rijndaelAlg.Mode = [CipherMode.CFB;] // Defaults to CBC mode. Use of ECB mode is not recommended
		                                                   ' as it provides no feedback chaining of ciphertext
	

		            'Set secret key For AES algorithm.
		            rijndaelAlg.Key = [ASCIIEncoding.ASCII.GetBytes(sKey)]
	

		            'Set initialization vector.
		            rijndaelAlg.IV = [ASCIIEncoding.ASCII.GetBytes(sIV)]
	

		            Dim fsPlaintext As [FileStream] =  New [FileStream(sInputFilename,FileMode.Open,FileAccess.Read)] 
		            Dim fsCiphertext As [FileStream] =  New [FileStream(sOutputFilename,FileMode.Create,FileAccess.Write)] 
	

		            'Create an AES encryptor from the AES instance.
		            Dim aesencrypt As [ICryptoTransform] =  [rijndaelAlg.CreateEncryptor()] 
	

		            'Create crypto stream set to read and do an AES encryption transform on incoming bytes.
		            Dim cipherstream As [CryptoStream] =  New [CryptoStream(fsCiphertext,aesencrypt,CryptoStreamMode.Write)] 
	

		            Dim bytearrayinput() As Byte =  New Byte(fsPlaintext.Length) {} 
		            fsPlaintext.Read(bytearrayinput, 0, bytearrayinput.Length)
		            cipherstream.Write(bytearrayinput, 0, bytearrayinput.Length)
		            cipherstream.Close()
		            fsPlaintext.Close()
		            fsCiphertext.Close()
		        End Sub
	


Problem Example

The following example demonstrates an implementation of a Encryption routine containing several common
secure coding issues.


		        Private  Sub [ProblematicFileEncrypt(ByVal] [sInputFilename] As String, [ByVal] [sOutputFilename] As String)
		            Dim rijndaelAlg As Rijndael =  Rijndael.Create() 
	

		            'Set secret key for the AES algorithm.
		            rijndaelAlg.Key = ASCIIEncoding.ASCII.GetBytes("_A_SAMPLE_KEY_WE_USE_TO_ENCRYPT_")
		            'We don't use an IV because the book doesn't show us an example using a 
		            'more secure, chained mode! If the book told us to jump off a bridge we probably would.
		            ' rijndaelAlg.IV = ASCIIEncoding.ASCII.GetBytes("SAMPLEIV");
	

		            'Set encryption mode to an unchained value (because the book says so!)
		            rijndaelAlg.Mode = [CipherMode.ECB]
	

		            'Create a file stream to read the plaintext contents in.
		            Dim fsPlaintext As [FileStream] =  New [FileStream(sInputFilename,FileMode.Open,FileAccess.Read)] 
		            Dim fsCiphertext As [FileStream] =  New [FileStream(sOutputFilename,FileMode.Create,FileAccess.Write)] 
	

		            'Create an AES encryptor
		            Dim aesencrypt As [ICryptoTransform] =  [rijndaelAlg.CreateEncryptor()] 
	

		            'Create crypto stream set to read and do an AES encryption transform on incoming bytes.
		            Dim cipherstream As [CryptoStream] =  New [CryptoStream(fsCiphertext,aesencrypt,CryptoStreamMode.Write)] 
	

		            'Write the contents of the encrypted file.
		            Dim bytearrayinput() As Byte =  New Byte(fsPlaintext.Length) {} 
		            fsPlaintext.Read(bytearrayinput, 0, bytearrayinput.Length)
		            cipherstream.Write(bytearrayinput, 0, bytearrayinput.Length)
		            cipherstream.Close()
		            fsPlaintext.Close()
		            fsCiphertext.Close()
		        End Sub
	


* Cleartext encryption key can be extracted by any user with access to the source code or compiled code
* Use of a weak encryption (non-random) key, which can be brute-forced using a dictionary attack
* Insecure cipher mode (ECB), performs encryption of each blocks 128 bits independently with no feedback into subsequent blocks as CBC and other chained modes do. An attacker can rearrange or replace blocks with previous blocks they observe.
* ECB mode does not utilize an initialization vector, yielding the same encrypted value for each plaintext value. An attacker can thus observe patterns in the encrypted blocks and perform known plaintext attacks (Note: Initialization vectors need not remain secret however they should be random for each encrypted value of the plaintext)

Test Case

The following classes must be included in any project making use of the sample code provided above:

Imports System
Imports System.Text
Imports System.IO
Imports System.Security.Cryptography

The following test case demonstrates the use of the DecryptFile function

		    Sub [Main(ByVal] args() As String)
		        ' Test case for file encryption routines
		        Console.Out.WriteLine("Encrypting: " + args(0) + " to file: " + args(1))
		        [EncryptFile(args(0),] args(1), sKey, sIV)
	

		        Console.Out.WriteLine("Decrypting: " + args(1) + " to file: " + args(0) + ".new")
		        [DecryptFile(args(1),] args(0) + ".new", sKey, sIV)
		    End Sub
	


* sKey and sIV are retrieved from the DataProtection API within Application code

Expected Result

Comparing the Decrypted file value with the original file text should yield the same text.


More Information

* Although AES defaults to 256-bit key sizes under the .NET framework, even under current cryptography standards, the default 128-bit key-size used by many crypto implementations is still considered secure.
* The test case assumes use of the DataProtection API implemented within the user code to securely store and retrieve encryption keys.


Additional Resources

* Protecting keys using the DPAPI: http://msdn.microsoft.com/library/en-us/dnpag2/html/paght000005.asp
* Cryptography (.NET): http://msdn.microsoft.com/library/en-us/dnpag2/html/PAGGuidelines0003.asp?frame=true#pagguidelines0003_cryptography

Attributes

* Applies To: .NET Framework 2.0, VB
* Category: Cryptography
* Author: George Gal




Return to HomePage
Microsoft Communities