Today I would like to cover a specific use case that came up a few times in Silverlight applications I wrote. For example, I wand a user to enter some sensitive information, encrypt it in Silverlight client, transfer it over to the server, then decrypt it and perforation some operations on that data.
First step of course is to find sufficiently strong encryption protocol that can be implemented in both Silverlight and .NET and be completely compatible between both run times. I am going to go for AES encryption. AES stands for “Advanced Encryption Standard”. This standard is widely used and approved by US government and standard bodies. See this article for details.
Luckily, AES encryption is implemented in both Silverlight and .NET run times, using exact same set of classes, primary one being AesManaged class. My goal is to create a class that I can cross-compile in both runt times, so this comes in super handy. Second, I wand to implement two methods Decrypt and Encrypt, while paying attention to IDisposable interfaces that the vast majority of classes inside Cryptography namespace implement. Both static methods take two parameters, input string and a password to be used. Of course, you have to make sure you use the same password in both methods while encrypting and decrypting information. You should probably dynamically generate a password during handshake process between a Silverlight client and a .NET server. I will also use maximum key size and block size of encryption. I will also dynamically generate key (Key) and initialization vector(IV) properties. I am going to now spare everyone a number of boring details, and will simply post final version of my utility class: You can include this class in both .NET and Silverlight project, and even link the physical .cs file from one to the other to ensure that you only have a single version in source control.
Thanks
using System;
using System.Text;
using System.Security.Cryptography;
using System.IO;
namespace Encryption
{
public static class EncryptionUtility
{
/// <summary>
/// Encrypt the data
/// </summary>
/// <param name="input">String to encrypt</param>
/// <returns>Encrypted string</returns>
public static string Encrypt(string input, string password)
{
byte[] utfData = UTF8Encoding.UTF8.GetBytes(input);
byte[] saltBytes = Encoding.UTF8.GetBytes(password);
string encryptedString = string.Empty;
using (AesManaged aes = new AesManaged())
{
Rfc2898DeriveBytes rfc = new Rfc2898DeriveBytes(password, saltBytes);
aes.BlockSize = aes.LegalBlockSizes[0].MaxSize;
aes.KeySize = aes.LegalKeySizes[0].MaxSize;
aes.Key = rfc.GetBytes(aes.KeySize / 8);
aes.IV = rfc.GetBytes(aes.BlockSize / 8);
using (ICryptoTransform encryptTransform = aes.CreateEncryptor())
{
using (MemoryStream encryptedStream = new MemoryStream())
{
using (CryptoStream encryptor =
new CryptoStream(encryptedStream, encryptTransform, CryptoStreamMode.Write))
{
encryptor.Write(utfData, 0, utfData.Length);
encryptor.Flush();
encryptor.Close();
byte[] encryptBytes = encryptedStream.ToArray();
encryptedString = Convert.ToBase64String(encryptBytes);
}
}
}
}
return encryptedString;
}
/// <summary>
/// Decrypt a string
/// </summary>
/// <param name="input">Input string in base 64 format</param>
/// <returns>Decrypted string</returns>
public static string Decrypt(string input, string password)
{
byte[] encryptedBytes = Convert.FromBase64String(input);
byte[] saltBytes = Encoding.UTF8.GetBytes(password);
string decryptedString = string.Empty;
using (var aes = new AesManaged())
{
Rfc2898DeriveBytes rfc = new Rfc2898DeriveBytes(password, saltBytes);
aes.BlockSize = aes.LegalBlockSizes[0].MaxSize;
aes.KeySize = aes.LegalKeySizes[0].MaxSize;
aes.Key = rfc.GetBytes(aes.KeySize / 8);
aes.IV = rfc.GetBytes(aes.BlockSize / 8);
using (ICryptoTransform decryptTransform = aes.CreateDecryptor())
{
using (MemoryStream decryptedStream = new MemoryStream())
{
CryptoStream decryptor =
new CryptoStream(decryptedStream, decryptTransform, CryptoStreamMode.Write);
decryptor.Write(encryptedBytes, 0, encryptedBytes.Length);
decryptor.Flush();
decryptor.Close();
byte[] decryptBytes = decryptedStream.ToArray();
decryptedString =
UTF8Encoding.UTF8.GetString(decryptBytes, 0, decryptBytes.Length);
}
}
}
return decryptedString;
}
}
}
Thanks for this, just what I was after, though needed it in VB:
Imports System.Text
Imports System.IO
Imports System.Security.Cryptography
Public Class Encryption
Public Shared Function Encrypt(ByVal decryptedString As String, ByVal password As String) As String
Dim encryptedString As String = String.Empty
Dim decryptedBytes As Byte() = UTF8Encoding.UTF8.GetBytes(decryptedString)
Dim saltBytes As Byte() = Encoding.UTF8.GetBytes(password)
Using aes As New AesManaged()
Dim rfc As New Rfc2898DeriveBytes(password, saltBytes)
aes.BlockSize = aes.LegalBlockSizes(0).MaxSize
aes.KeySize = aes.LegalKeySizes(0).MaxSize
aes.Key = rfc.GetBytes(CInt(aes.KeySize / 8))
aes.IV = rfc.GetBytes(CInt(aes.BlockSize / 8))
Using encryptTransform As ICryptoTransform = aes.CreateEncryptor()
Using encryptedStream As New MemoryStream()
Using encryptor As New CryptoStream(encryptedStream, encryptTransform, CryptoStreamMode.Write)
encryptor.Write(decryptedBytes, 0, decryptedBytes.Length)
encryptor.Flush()
encryptor.Close()
Dim encryptedBytes() As Byte = encryptedStream.ToArray()
encryptedString = Convert.ToBase64String(encryptedBytes)
End Using
End Using
End Using
End Using
Return encryptedString
End Function
Public Shared Function Decrypt(ByVal encryptedString As String, ByVal password As String) As String
Dim decryptedString As String = String.Empty
Dim encryptedBytes() As Byte = Convert.FromBase64String(encryptedString)
Dim saltBytes As Byte() = Encoding.UTF8.GetBytes(password)
Using aes As New AesManaged()
Dim rfc As New Rfc2898DeriveBytes(password, saltBytes)
aes.BlockSize = aes.LegalBlockSizes(0).MaxSize
aes.KeySize = aes.LegalKeySizes(0).MaxSize
aes.Key = rfc.GetBytes(CInt(aes.KeySize / 8))
aes.IV = rfc.GetBytes(CInt(aes.BlockSize / 8))
Using decryptTransform As ICryptoTransform = aes.CreateDecryptor()
Using decryptedStream As New MemoryStream()
Using decryptor As New CryptoStream(decryptedStream, decryptTransform, CryptoStreamMode.Write)
decryptor.Write(encryptedBytes, 0, encryptedBytes.Length)
decryptor.Flush()
decryptor.Close()
Dim decryptedBytes() As Byte = decryptedStream.ToArray()
decryptedString = Convert.ToBase64String(decryptedBytes)
End Using
End Using
End Using
End Using
Return decryptedString
End Function
End Class
Whoops:
decryptedString = Convert.ToBase64String(decryptedBytes)
Should Be:
decryptedString = UTF8Encoding.UTF8.GetString(decryptedBytes, 0, decryptedBytes.Length)
Thanks Sergey for this important code. Very good written.
Thank You man!
Very nice article, thank you!
Thank you for the code.
I have aproblem with it, I send am encripted string with your code form a silverlight App, an recive it in a windows service, but alwais have te same error about Padding:
“Padding is invalid and can not be removed”.
This error jump in decryptor.Close()
Do you have an idea about How can I resolve the problem?.
Thanks
mge – Spain —
Maybe encoding is not compatible with encrypted text? Or the key is different?
Pingback: SQL Azure, Entity Framework and HIPAA | Sergey Barskiy's Blog