C# – RSA encryption and decryption

Many software use RSA algorithm for generating serial key and protecting it from cracker to release key generator because RSA algorithm is too much complex. Cracking RSA private key from the public key encrypted with 1024 bit, is really not possible with power of current computer. Therefore RSA was applied in many security fields, especially in public key communication. There are a lot of articles on Internet describing how it works so I do not intend to discuss about this algorithm again in this blog. I just would like to make a small example to show how we encrypt and decrypt data with RSA which in some cases will help us to protect our data.
Usually when we encrypt and decrypt data, both of process will need the same key. However RSA allows us to encrypt data with a public key and decrypt data with another key. In .Net, we’ll use RSACryptoServiceProvider as our RSA engine.

1. Desktop

1. Intialize RSA Provider and assign parameters

private static RSACryptoServiceProvider GetRSACryptoServiceProvider()
{
	const int PROVIDER_RSA_FULL = 1;
	const string CONTAINER_NAME = "HintDeskRSAContainer";

	var cspParams = new CspParameters(PROVIDER_RSA_FULL)
	{
		KeyContainerName = CONTAINER_NAME,
		Flags = CspProviderFlags.UseMachineKeyStore,
		ProviderName = "Microsoft Strong Cryptographic Provider"
	};


	var sid = new SecurityIdentifier(WellKnownSidType.WorldSid, null);
	var account = (NTAccount)sid.Translate(typeof(NTAccount));
	if (account != null)
	{
		CryptoKeyAccessRule rule = new CryptoKeyAccessRule(account.Value, CryptoKeyRights.FullControl, AccessControlType.Allow);
		cspParams.CryptoKeySecurity = new CryptoKeySecurity();
		cspParams.CryptoKeySecurity.SetAccessRule(rule);
	}


	return new RSACryptoServiceProvider(1024, cspParams);
}

2. Generate public, private key and store them in XML file

public static void GetPublicAndPrivateKey(out string privateKey, out string publicKey)
{
	RSACryptoServiceProvider rsaCryptoServiceProvider = GetRSACryptoServiceProvider();
	privateKey = rsaCryptoServiceProvider.ToXmlString(true);
	publicKey = rsaCryptoServiceProvider.ToXmlString(false);
}

3. Encrypt and decrypt data

public static string EncryptData(string publicKey, string clearText)
{
	RSACryptoServiceProvider rsaCryptoServiceProvider = GetRSACryptoServiceProvider();
	publicKey = string.IsNullOrWhiteSpace(publicKey) ? DefaultPublicKey : publicKey;
	rsaCryptoServiceProvider.FromXmlString(publicKey);
	byte[] baPlainbytes = Encoding.UTF8.GetBytes(clearText);
	byte[] baCipherbytes = rsaCryptoServiceProvider.Encrypt(baPlainbytes, false);
	return Convert.ToBase64String(baCipherbytes);
}

public static string DecryptData(string privateKey, string encryptedText)
{
	try
	{
		RSACryptoServiceProvider rsaCryptoServiceProvider = GetRSACryptoServiceProvider();
		privateKey = string.IsNullOrWhiteSpace(privateKey) ? DefaultPrivateKey : privateKey;
		byte[] baGetPassword = Convert.FromBase64String(encryptedText);
		rsaCryptoServiceProvider.FromXmlString(privateKey);
		byte[] baPlain = rsaCryptoServiceProvider.Decrypt(baGetPassword, false);
		return Encoding.UTF8.GetString(baPlain);
	}
	catch (Exception ex)
	{
		throw;
	}
}

To use this class, first we must assign (generate) new key and call static functions for encrypting and decrypting.

[TestMethod]
public void GetPublicAndPrivateKey_NoException()
{
	string privateKey, publicKey;
	RSAEngine.GetPublicAndPrivateKey(out privateKey, out publicKey);
	Assert.IsTrue(!string.IsNullOrWhiteSpace(privateKey));
	Assert.IsTrue(!string.IsNullOrWhiteSpace(publicKey));
}

[TestMethod]
public void EncryptDecrypt_MustBeCorrect()
{
	const string clearText = "{BE85D19D-7154-4A8D-8C26-9870301E5AC0}";
	string encryptedText = RSAEngine.EncryptData(null, clearText);
	string decryptedText = RSAEngine.DecryptData(null, encryptedText);

	Assert.AreEqual(clearText, decryptedText);
}

2. Universal app

For universal app, you can use following code listing

public class RSAUtil
{
	private const string DefaultPrivateKey =
		@"BwIAAACkAABSU0EyAAQAAAEAAQAjfuX1laEPF1NlrgYD3vaoncHvsj+aHUnxcXSEUXQpGfKu4AruI5q110dEgUTSuBVnNC5Zi1hK3x3D6bCE3lZbVXeXvvzFkd/4YIj962Enu+9RjIf6cVdG2DPNCy5bYAjAujPLfrpqafqB86Tvnx90EYox7YAGjppLXYGFJTKG/edIKqHfjRWnPaXzrC0/6CSOls9lbCBDfc/C7+pIb7nvpEsVcCviOxL3fE+fpa418xjg8z+AAiP2qF6egNTXwP5lDQUCIYunHCghjMPmyQfPZFc4KIRxV0ZZ7yYi8iYYVuz/L9idzxkWjN2u9kXlzAukHndM2DgSbaLjPb8f0MP+00f2/3WSMycEguFgLEgkwL/XZgZKKtI2rBi/0MK7YaiNgmYJIy5GrouTMSkWUQMPBO5GcPvFITYXMHDq7N4g2gEAWEMp/Z7liiG/5iPKVShsC20Kof+/3NV0AEeJQTPIUk2osmPDg7ACVWBiSxsGHu3ku+JhMNRdcD14O1e0sD8hbBmINXP1mC+NlnUjp6GzuyvBkq2opEazCiRxqVOQDf2Bl2w57pGk9xVJjPlPnUUA4Zkuj3UwuHasJJEVJ4g7+XdCunB5m0rYXb5iiRkVAw8sJj095YRqmJbgNSL9mMBadeIAQVgrVKexvPDp+MI36Scly+oAcxdMFuWq4Zqaa2aP5OBZKqQOtE80k6KdCWgzte6DKjxlZjfOADtPAuEcwvK+nXMr+nAjEcVDKkXhS59PsHbiK9gO8H+oCe1ppnU=";

	private const string DefaultPublicKey =
		@"BgIAAACkAABSU0ExAAQAAAEAAQAjfuX1laEPF1NlrgYD3vaoncHvsj+aHUnxcXSEUXQpGfKu4AruI5q110dEgUTSuBVnNC5Zi1hK3x3D6bCE3lZbVXeXvvzFkd/4YIj962Enu+9RjIf6cVdG2DPNCy5bYAjAujPLfrpqafqB86Tvnx90EYox7YAGjppLXYGFJTKG/Q==";

	public static string DecryptData(string privateKey, string encryptedText)
	{
		privateKey = string.IsNullOrWhiteSpace(privateKey) ? DefaultPrivateKey : privateKey;
		byte[] encryptedTextBytes = Convert.FromBase64String(encryptedText);
		IBuffer keyBuffer = CryptographicBuffer.DecodeFromBase64String(privateKey);
		AsymmetricKeyAlgorithmProvider asym = AsymmetricKeyAlgorithmProvider.OpenAlgorithm(AsymmetricAlgorithmNames.RsaPkcs1);
		CryptographicKey key = asym.ImportKeyPair(keyBuffer, CryptographicPrivateKeyBlobType.Capi1PrivateKey);
		IBuffer plainBuffer = CryptographicEngine.Decrypt(key, encryptedTextBytes.AsBuffer(), null);
		byte[] plainBytes;
		CryptographicBuffer.CopyToByteArray(plainBuffer, out plainBytes);
		return Encoding.UTF8.GetString(plainBytes, 0, plainBytes.Length);
	}

	public static string EncryptData(string publicKey, string clearText)
	{
		publicKey = string.IsNullOrWhiteSpace(publicKey) ? DefaultPublicKey : publicKey;
		IBuffer keyBuffer = CryptographicBuffer.DecodeFromBase64String(publicKey);
		AsymmetricKeyAlgorithmProvider asym = AsymmetricKeyAlgorithmProvider.OpenAlgorithm(AsymmetricAlgorithmNames.RsaPkcs1);
		CryptographicKey key = asym.ImportPublicKey(keyBuffer, CryptographicPublicKeyBlobType.Capi1PublicKey);
		IBuffer plainBuffer = CryptographicBuffer.ConvertStringToBinary(clearText, BinaryStringEncoding.Utf8);
		IBuffer encryptedBuffer = CryptographicEngine.Encrypt(key, plainBuffer, null);
		byte[] encryptedBytes;
		CryptographicBuffer.CopyToByteArray(encryptedBuffer, out encryptedBytes);
		return Convert.ToBase64String(encryptedBytes);
	}

	public static void GetPublicAndPrivateKey(out string privateKey, out string publicKey)
	{
		AsymmetricKeyAlgorithmProvider asym = AsymmetricKeyAlgorithmProvider.OpenAlgorithm(AsymmetricAlgorithmNames.RsaPkcs1);
		CryptographicKey key = asym.CreateKeyPair(1024);
		IBuffer privateKeyBuffer = key.Export(CryptographicPrivateKeyBlobType.Capi1PrivateKey);
		IBuffer publicKeyBuffer = key.ExportPublicKey(CryptographicPublicKeyBlobType.Capi1PublicKey);
		byte[] privateKeyBytes;
		byte[] publicKeyBytes;
		CryptographicBuffer.CopyToByteArray(privateKeyBuffer, out privateKeyBytes);
		CryptographicBuffer.CopyToByteArray(publicKeyBuffer, out publicKeyBytes);
		privateKey = Convert.ToBase64String(privateKeyBytes);
		publicKey = Convert.ToBase64String(publicKeyBytes);
	}
}

3. Source code

Source code of Desktop: https://bitbucket.org/hintdesk/dotnet-rsa-encryption-and-decryption

Source code of Universal App: https://bitbucket.org/hintdesk/dotnet-hdunilib

One thought on “C# – RSA encryption and decryption”

  1. Hey! good post!
    question:
    1. I have part of the original text (I have the first sentence of the original text)
    2. I have the whole text encrypted in RSA key: 128
    How can I get the whole original text that has been encrypted?
    Thx!

Leave a Reply

Your email address will not be published. Required fields are marked *