I have been looking at encrypting and decrypting data as part of a project that I’m doing at work. As is quite common there’s a ton of stuff on the internet but the devil as always is in the details. What appears to work for one person won’t necessary work for another.
I don’t want to talk too much about how encryption and decryption works, partly because I’m not an expert so there are a few things I’m bound to get wrong. Also it is a separate topic in itself. There are however two fundamental things that you need to be aware of: these are the Public Key and the Private Key. The Public Key as its name suggests can be shared with the public, the private key should be kept private. The other thing to be aware of from a coding point of view is that there are a number of different ways to do this. I tried quite a few of them but not all. The reason for this is trying to keep the details used to encrypt safe.
The private key can be used to decrypt messages and the public key can be used to encrypt messages. I think that when passing encrypted data between two parties, Alice and Bob, then both will need to have the same private key to decrypt. When reading articles about cryptography it’s very common to read about Alice and Bob.
The purpose of this article is make some notes about the code that works for me, and explain some of the areas which tripped me up and caused me some problems.
The code at the bottom of this article is the working version I got to this morning. There are a things to note. First, I’m using two X509Certificates, an CER file and a PFX file. You could just use the PFX file, since this contains both the private and public key, the CER file doesn’t contain the private key. If you had a scenario where Bob needed to send encrypted messages to Alice then he would just need the CER. Alice could keep her private key and decrypt messages she receives from Bob.If Bob wanted to read encrypted messages from Alice then he would also need the private key.
The most common exception I got was ‘the key does not exist’. There can be a number of reasons why this happens but all the solutions I saw online didn’t help me. It wasn’t until I added a third parameter in the X509Certificate import: the X509KeyStorageFlags.Exportable parameter when things started working. And I only found out I really needed this through trial and error and getting this exception ‘key not valid for use in specified state’. And I only started getting that error when I tried using the ImportParameters method of the RSACryptoServiceProvider. There were also a number of problems with the
These links on StackOverflow helped me and contain information that I found useful
- Key does not exist exception thrown. What am I doing wrong? This gave me an idea that I needed to import parameters.
- Trying to decrypt using a public key. The answer is very informative.
- Key not valid for use in specified state while trying to export RSAParameters. This highlighted the need for a third parameter.
- And although it wasn’t directly relevant to what I was doing. This is a nice guide to AES encryption in C#
- Another article that I saw but didn’t use was this concerning EncryptedXml. It looks like it could be useful.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.IO;
namespace EncryptionAndDecryption {
class Program {
static void Main(string[] args) {
string textToEncrypt = “The quick red fox jumps over the lazy brown dog”;
string encryptedText = Crypto.Encrypt(textToEncrypt);
string decryptedText = Crypto.Decrypt(encryptedText);
Console.ReadLine();
}
}
static public class Crypto {
public static X509Certificate2 GetPublicKey() {
return new X509Certificate2(@”c:\TestCertificates\testCertificate.cer”,
“”,
X509KeyStorageFlags.Exportable);
}
public static X509Certificate2 GetPrivateKey() {
return new X509Certificate2(@”c:\TestCertificates\testPFX.pfx”,
“password”,
X509KeyStorageFlags.Exportable);
}
public static string Encrypt(string textToEncrypt) {
ASCIIEncoding byteConverter = new ASCIIEncoding();
byte[] encodedBytes = byteConverter.GetBytes(textToEncrypt);
X509Certificate2 cert = GetPublicKey();
byte[] encryptedBytes;
RSACryptoServiceProvider rsa = cert.PublicKey.Key as RSACryptoServiceProvider;
encryptedBytes = rsa.Encrypt(encodedBytes, false);
return Convert.ToBase64String(encryptedBytes);
}
public static string Decrypt(string encryptedText) {
byte[] encryptedBytes = Convert.FromBase64String(encryptedText);
X509Certificate2 cert = GetPrivateKey();
RSACryptoServiceProvider rsa = cert.PrivateKey as RSACryptoServiceProvider;
byte[] decryptedBytes;
decryptedBytes = rsa.Decrypt(encryptedBytes, false);
ASCIIEncoding byteConverter = new ASCIIEncoding();
return byteConverter.GetString(decryptedBytes);
}
} //End of class Crypto
}