Keep your Data Protected with a Microsoft Partner

Encryption, Keys and Cryptographic Key Containers

Security and Cryptography go hand in hand. To build secure applications, along with authenticating users, you also need to keep data protected and ensure that no one tampers it. Cryptography is the science of Encrypting and Decrypting data.

Perfect way to secure data is to keep it locked down and protected. But that’s never the case, Data is never stationary, it must travel and shake hands with the outside world. So, we must prepare Data so that it is ready to face adversities and withstand malicious probing. Huh … I may use this analogy on my kids someday when they are ready to leave the nest.

We can “Prepare” data to leave the nest by Encrypting it and on its return journey we can Decrypt it back. Imagine you have an expensive jewel (Data) that you are travelling with (Data Transfer), and to hide it from thieves, you put it in a jewel box and lock it with a key (Encrypted with a Key) and that key is safely stashed away (Key Container). My blog will explain in detail about Data Encryption and Decryption.

Encryption

Encryption is turning human readable data into some gibberish. When I was a kid, we had a secret language that only we could understand, at least that is what we thought back then!
‘Hello’ would be ‘Kgoor’

This is Encryption in a simple, plain form. We simply moved each letter by 3 alphabets to get the encoded word. This acted as our Algorithm. If our Algorithm leaked, then any one could decode the text. We soon realized that we needed extra Security, some sort of Key.

In professional world, there are complex Algorithms such as DES (Data Encryption Standard), AES (Advanced Encryption Standard), etc. These Algorithms are intentionally made public, and people are challenged to break them; resulting in products that are strong, well established Algorithms. Added security comes in the form of a Key, as these Algorithm work only with keys.

Encryption is categorized into Symmetric and Asymmetric depending on how keys are used. Symmetric uses a single key and Asymmetric uses a pair of key.

Symmetric Encryption

In Symmetric algorithm, one single key is used to encrypt and decrypt data. When encrypted data is exchanged, we also need to exchange the key. If this key is obtained by a malicious user, he can use it to easily decrypt data. It is like you locked your jewel in a box and secured it with a lock and then put the key right next to the lock!!

Of course, you can send key and messages separately, which will make it a little difficult for the snooper as he would not know which key will go into which lock. But there are ways to easily crack that, and once a copy of key is made you data is no longer confidential. For highly sensitive data, you would not want to share or exchange your key, and this is when Asymmetric Encryption comes into play. More on that shortly.

.Net Framework offers implementations for various cryptographic algorithms under the namespace System.Security.Cryptography. One such Symmetric algorithm AES is implemented in AesManaged class. Using this we can create a key and Encrypt/Decrypt text using CryptoStream class.

public static void EncryptSomeText()
{
string original = “My highly precious data!”;
using (SymmetricAlgorithm symmetricAlgorithm = new AesManaged())
{
byte[] encrypted = Encrypt(symmetricAlgorithm, original);
string roundtrip = Decrypt(symmetricAlgorithm, encrypted);

Console.WriteLine(“Original Data: { 0}”, original);
Console.WriteLine(“Round Trip: { 0}”, roundtrip);
}
}

static byte[] Encrypt(SymmetricAlgorithm aesAlg, string plainText)
{
ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);
using (MemoryStream msEncrypt = new MemoryStream())
{
using (CryptoStream csEncrypt =
new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
{
using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
{
swEncrypt.Write(plainText);
}
return msEncrypt.ToArray();
}
}
}

static string Decrypt(SymmetricAlgorithm aesAlg, byte[] cipherText)
{
ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);
using (MemoryStream msDecrypt = new MemoryStream(cipherText))
{
using (CryptoStream csDecrypt =
new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
{
using (StreamReader srDecrypt = new StreamReader(csDecrypt))
{
return srDecrypt.ReadToEnd();
}
}
}
}

Code Line SymmetricAlgorithm symmetricAlgorithm = new AesManaged(), creates a Key with some IV factor to add some randomness to it. The SymmetricAlgorithm class has both a method for creating an encryptor and a de¬cryptor which are used above.

Here is the output. Encrypted data is different every time you run the application as a new Key is generated. Decrypt function above uses the same default Key created by the constructor of AesManaged, but in real application the key used in Encryption is retrieved and saved safely, and a copy is transported to the receiver who will use it for Decrypting data.

 
Asymmetric Encryption

Asymmetric Encryption work with a pair of key, Public and Private. They are mathematically related to each other, but you cannot determine one when you know the other. Private key stays with the Sender and Public key is distributed to the parties interested in send messages or is published online. So instead of a jewel box and key analogy that I used for Symmetric Encryption, Asymmetric Encryption is like a Post box where anyone can post letters for me using my post box address (aka public key) but only I can unlock the post box using my private key.

The .NET Framework also has support for asymmetric encryption. You can use the RSACryptoServiceProvider and DSACryptoServiceProvider classes. When working with asymmetric encryption, you typically use the public key from another party. You encrypt the data using the public key so only the other party can decrypt the data with their private key.
Here is how you can create a public and private key pair using RSACryptoServiceProvider. Using ToXMLString() method you can extract keys, when true is passed to this method, you get private key, false gives you public key.

private static void GenerateKeyPair(out string publicKeyXML, out string privateKeyXML)
{
// New instance of RSACryptoProvider will create a public-private key pair
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
publicKeyXML = rsa.ToXmlString(false);
privateKeyXML = rsa.ToXmlString(true);

Console.WriteLine(publicKeyXML);
Console.WriteLine(privateKeyXML);
}

private static byte[] EncryptData(string publicKeyXML, byte[] plainText)
{
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
rsa.FromXmlString(publicKeyXML);
return rsa.Encrypt(plainText, false);
}

private static byte[] DecryptData(string privateKey, byte[] cipherText)
{
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
rsa.FromXmlString(privateKey);
return rsa.Decrypt(cipherText, false);
}

Here is the output screen, showing Public and Private keys in a string format.

Best of both Worlds: Symmetric + Asymmetric

Symmetric Algorithms work better on large stream of data and are less expensive, Asymmetric provide better security but are good for small data such as passwords. Combining these two techniques we can efficiently Encrypt/Decrypt Data. First, data is encrypted using Symmetric Algorithm, then, instead of transporting the key as is, it is encrypted using Receiver’s Public Key. Receivers receives Encrypted Key which he then decrypts using his Private key. Decrypted key can then be used to Decrypt the transported data.

Key Containers

In the code segments above, we generated both public and private keys. While it is okay to share the public keys, private keys need to be kept safe. The private key should never be stored in plain text on the hard drive. Keys Containers are used to safely store keys.

Key Containers are not fancy looking as shown in the picture above, they are simple FOLDERS! In Windows OS, there are two locations where the keys are stored, one is at the machine level and another is at user level.

Machine Level RSA Key Container path is C:\ProgramData\Microsoft\Crypto\RSA\MachineKeys

User-Level RSA Key Container path is C:\Users\mwad\AppData\Roaming\Microsoft\Crypto\RSA\

If you open one of the file in the container then you will see that it is encrypted.

Here is the code to generate and retrieve a key in Key Container.

 

private static void GenerateKey(string keyContainerName)
{
CspParameters csp = new CspParameters();
csp.KeyContainerName = keyContainerName;
csp.Flags = CspProviderFlags.UseMachineKeyStore;

// New instance of RSACryptoProvider will create a public-private key pair
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(csp);
rsa.PersistKeyInCsp = true;

// ToXMLString gives the key info, public for false and private for true

string publicKey = rsa.ToXmlString(false);
string privateKey = rsa.ToXmlString(true);

// Display the key information to the console.
Console.WriteLine(“Public Key added to container: \n {0}”, publicKey);
Console.WriteLine(“Private Key added to container: \n {0}”, privateKey);

CspKeyContainerInfo info = new CspKeyContainerInfo(csp);
Console.WriteLine($”The key container name: {info.KeyContainerName}”);
Console.WriteLine($”Unique key container name: {info.UniqueKeyContainerName}”);
}

We provide a container name to CspParameters which can be used later to retrieve the key. ‘csp’ is passed to RSACryptoServiceProvider constructor. Also, the flag is set to indicate that ley will be saved as a Machine-level key.

Importing and Exporting Keys from Key Container
In Asymmetric Encryption, we need to provide our public key to the senders who want to send us messages. This requires us to export the public key from the Key Container into a text file which can then be circulated. On the other hand, if other people gave us their public key then we need to Import it into the Key Container. Here is the code for that.

private static string ExportPublicKey(string containerName)
{
CspParameters csp = new CspParameters();
csp.KeyContainerName = containerName;
csp.Flags = CspProviderFlags.UseMachineKeyStore;

RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(csp);
return rsa.ToXmlString(false);
}

private static void ImportPublicKey(string privateKeyText, string containerName)
{
CspParameters csp = new CspParameters();
csp.KeyContainerName = containerName;
csp.Flags = CspProviderFlags.UseMachineKeyStore;

RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(csp);
rsa.FromXmlString(privateKeyText);
}

Share this post

Related Posts

Checking Your CMMC Progress

Written by Alec Toloczko With Cybersecurity Maturity Model Certification (CMMC) requirements on the horizon, it’s crucial for organizations handling Controlled Unclassified Information (CUI) to adhere

Read More »