Return to HomePage



Decrypt a string 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 to decrypt strings of text within an application. This test case utilizes AES (Rijndael) which serves as the current NIST encryption standard.


Objectives

* To provide confidentiality of data which is transmitted over insecure or untrusted communication channels.
* To provide confidentiality of data in storage until it is needed by a user or application


Solution Example


		        Public Function [DecryptString(ByVal] ciphertext As String, [ByVal] sKey() As Byte, [ByVal] sIV() As Byte) 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() 
	

		            'Set secret key For AES algorithm.
		            rijndaelAlg.Key = sKey
	

		            'Set initialization vector.
		            rijndaelAlg.IV = sIV
	

		            'Create a memorystream to which we'll decrypt our input string
		            Dim ms As [MemoryStream] =  New [MemoryStream()] 
		            Dim ecs As [CryptoStream] =  New [CryptoStream(ms,rijndaelAlg.CreateDecryptor(),CryptoStreamMode.Write)] 
	

		            'Because the input string is passed in as a Base64 encoded value we decode prior writing to 
		            'the decryptor stream.
		            [ecs.Write(Convert.FromBase64String(ciphertext),] 0, [Convert.FromBase64String(ciphertext).Length)]
	

		            ecs.Close()
		            Return [ASCIIEncoding.ASCII.GetString(ms.ToArray())]
		        End Function
	



Problem Example

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

		        Public Function [ProblematicDecryptString(ByVal] ciphertext As String) 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 memorystream to which we'll decrypt our input string
		            Dim ms As [MemoryStream] =  New [MemoryStream()] 
		            Dim ecs As [CryptoStream] =  New [CryptoStream(ms,rijndaelAlg.CreateDecryptor(),CryptoStreamMode.Write)] 
	

		            'Because the input string is passed in as a Base64 encoded value we decode prior writing to 
		            'the decryptor stream.
		            [ecs.Write(Convert.FromBase64String(ciphertext),] 0, [Convert.FromBase64String(ciphertext).Length)]
	

		            ecs.Close()
		            Return [ASCIIEncoding.ASCII.GetString(ms.ToArray())]
		        End Function
	


* 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 DecryptString function

		        Sub [Main(ByVal] args() As String)
		            Dim enc As String,p2 As String,probenc As String,probp2 As String =  Nothing 
	

		            Dim aes As Rijndael =  Rijndael.Create() 
	

		            ' Test case for string encryption routines
		            Dim p1 As String =  "the quick brown fox jumped over the lazy dog" 
	

		            ' Run our test case multiple times to demonstrate different IV / encrypted text for each
		            ' iteration in when using proper crypto modes.
		            Console.Out.WriteLine("Solution test cases - notice varied output for static input")
		            Console.Out.WriteLine("-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-")
		            Dim i As Integer
		            For  i = 0 To  5- 1  Step  i + 1
		                aes.GenerateIV()
		                enc = [EncryptString(p1,] aes.Key, aes.IV)
		                Console.WriteLine("Encrypted text #{0}: " + enc, i)
		                p2 = [DecryptString(enc,] aes.Key, aes.IV)
	

		                Console.WriteLine("Plaintext #{0}: " + p2, i)
		                If Not p1.Equals(p2) Then
		                    Console.Error.WriteLine("Decryption failed")
		                End If
		            Next
	

		            ' Now run out problem test cases
		            Console.Out.WriteLine("Problem test cases - notice repetitive encrypted value")
		            Console.Out.WriteLine("-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-")
		            Dim i As Integer
		            For  i = 0 To  5- 1  Step  i + 1
		                probenc = [ProblematicEncryptString(p1)]
		                probp2 = [ProblematicDecryptString(probenc)]
		                Console.WriteLine("Encrypted text #{0}: " + probenc, i)
		                Console.WriteLine("Plaintext #{0}: " + probp2, i)
		            Next
		        End Sub
	


* In this test case AES encryption keys and initialization vectors are chosen at random during the call to Rijndael.Create().
* In a real-world implementation sKey and sIV should be retrieved from the Data Protection API within application code please refer to code sample demonstrating use of Data Protection API.

Expected Result

Solution test cases - notice varied output for static input
Encrypted text #0: PSQ7SRIFtv3W1GzSdsMCWR6ANZVZ78xjMG2ssQpsfyiWDMY3Wf+15Icd4XDEKhe8
Plaintext #0: the quick brown fox jumped over the lazy dog
Encrypted text #1: feBRJPILiia74FQnOpXlpIICYmieLbujF11yTkQyNitUPl35qf0aVd+VjYxyXVCL
Plaintext #1: the quick brown fox jumped over the lazy dog
Encrypted text #2: DfnDt3dO6eq3tdp3OC/5/zs6GN8jm2SUSqy50d1cwsHmQ4R+XsEttzT/7wlXXwuc
Plaintext #2: the quick brown fox jumped over the lazy dog
Encrypted text #3: lbU6t2jc5eVNBZEr6jQDEpj4/vfrjcqke/94X6pY8mEBlYJ4qyzUJEtFQf96Cm5W
Plaintext #3: the quick brown fox jumped over the lazy dog
Encrypted text #4: /by8DZLmxBpkP5fEbGw8UKXz6bmNa2IPedCgpcSdO65uNAf+ujJ2FV2EsZaTg19A
Plaintext #4: the quick brown fox jumped over the lazy dog

Problem test cases - notice repetitive encrypted value
Encrypted text #0: S/PCsy2/87IRuRzAjeHxXw3XUEfhwZ9Ol1Bai1Hy7RqFq9+V6ZIEHlo1IwRQjCVT
Plaintext #0: the quick brown fox jumped over the lazy dog
Encrypted text #1: S/PCsy2/87IRuRzAjeHxXw3XUEfhwZ9Ol1Bai1Hy7RqFq9+V6ZIEHlo1IwRQjCVT
Plaintext #1: the quick brown fox jumped over the lazy dog
Encrypted text #2: S/PCsy2/87IRuRzAjeHxXw3XUEfhwZ9Ol1Bai1Hy7RqFq9+V6ZIEHlo1IwRQjCVT
Plaintext #2: the quick brown fox jumped over the lazy dog
Encrypted text #3: S/PCsy2/87IRuRzAjeHxXw3XUEfhwZ9Ol1Bai1Hy7RqFq9+V6ZIEHlo1IwRQjCVT
Plaintext #3: the quick brown fox jumped over the lazy dog
Encrypted text #4: S/PCsy2/87IRuRzAjeHxXw3XUEfhwZ9Ol1Bai1Hy7RqFq9+V6ZIEHlo1IwRQjCVT
Plaintext #4: the quick brown fox jumped over the lazy dog

Scenarios

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

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