How to store the asymmetric keys in the Windows key store with C#

Introduction

In this post we briefly looked through asymmetric encryption in .NET. This encryption type requires two keys as opposed to symmetric encryption where the same key is used for encryption and decryption. In asymmetric encryption we have a public and a private key. The public key can be distributed so that other people can encrypt their messages to us. Then we use our private key to decrypt the ciphertext and read the original message. Therefore we don’t have to worry about the public key getting into the wrong hands. On the other hand asymmetric encryption is significantly slower than symmetric encryption due to the higher mathematical complexity.

In the post referenced above we saw how to store the asymmetric key-pair in an XML string. You can save this string in a file or database for later retrieval. There’s at least one more option for storage which is the cryptographic key store on Windows. We’ll go through how to use it in this post.

Read more of this post

Advertisements

Overview of asymmetric encryption in .NET

Introduction

Asymmetric encryption is based on a pair of cryptographic keys. One of the keys is public, i.e. anyone can have access to it. The other key is private which should be kept secret. The keys are complementary which means that they go hand in hand, they are not independent of each other. If a value is calculated as the public key then the private key cannot be calculated independently otherwise the encryption process will fail. Normally the public key is used to encrypt a message and the private key is there for the decryption process but they can be used in the opposite direction as well. Asymmetric algorithms are also called Public Key Cryptography.

The most important advantage of asymmetric over symmetric encryption is that we don’t need to worry about distributing the public key. The key used in symmetric encryption must be known to all parties taking part in the encryption/decryption process which increases the chances of the key landing in the wrong hands. With asymmetric encryption we only need to worry about storing the private key, the public key can be freely distributed. For a hacker it is not practical to attempt to calculate the private key based on the public key, that is close to impossible to achieve.

However, asymmetric encryption is a very complex mathematical process which is a lot slower than symmetric encryption. Also, storing the private key can still be problematic.

Read more of this post

Overview of symmetric encryption in .NET

Introduction

A symmetric encryption algorithm is one where the cryptographic key is the same for both encryption and decryption and is shared among the parties involved in the process.

Ideally only a small group of reliable people should have access to this key. Attackers decipher an encrypted message rather than trying to defeat the algorithm itself. The key can vary in size so the attacker will need to know this first. Once they know this then they will try combinations of possible key characters.

A clear disadvantage with this approach is that distributing and storing keys in a safe and reliable manner is difficult. On the other hand symmetric algorithms are fast.

In this short overview we’ll look at the symmetric encryption algorithms currently supported in .NET.

Read more of this post

Using HMACs to authenticate a hash in .NET

In this post we learnt about using hashing in .NET. Hashes provide a one-way encryption of a message where the hash value ideally cannot be “unhashed”, i.e. we cannot build the original string from it. A hash or message digest helps us verify whether the message has been tampered with by a third party after it was sent to us.

We can take a step further and add an extra layer of security on our hashes. After all a message and its hash could originate from anyone. How can we verify the authenticity of the message as well? That’s where Hashed Message Authentication Codes, also called HashMACs or HMACs enter the picture.

Read more of this post

Hashing messages using various hash algorithms in .NET

A hash of a message can be viewed as its unique identifier. A series of bytes, such as a string, can be converted into hash, also called a message digest. A message digest is also a byte array that can be converted into a base 64 string for better readability. There are various hashing algorithms out there that can calculate the hash of a message. Ideally each algorithm should produce a different digest for each message, i.e. “Hello world” should yield a different hash from what “H3llo world” produces. I.e. a single change in the byte sequence will change the resulting hash. Also, it should be impossible to calculate the original message from a hash. Therefore hashing is a one-way cryptographic operation.

Read more of this post

Generate truly random cryptographic keys using a random number generator in .NET

The well-known System.Random class lets us generate random numbers quickly. However, the values provided by System.Random are not truly random. Instead, they are pseudo-random. The return values should only be used in case true randomness is not that important, such as in the classic number-guessing game. In case you need a random value to be used in cryptography such as a cryptographic key in symmetric and asymmetric encryption then System.Random is not an acceptable option.

Read more of this post

An encrypted messaging project in .NET with C# part 5: processing the encrypted message

We finished off the previous post with the Sender sending the ingredients of the secret message to the Receiver:

  • The unique message ID
  • The encrypted AES public key
  • The AES cipher text
  • The AES initialisation vector

Now it’s up to the Receiver to decrypt the message. In case you don’t understand some code specific to encryption in .NET please refer to my previous blog posts on the topic.

Demo

Open the Receiver project we’ve been working on. Add the following interface to the Interfaces folder of the ApplicationService layer:

public interface ISecretMessageProcessingService
{
	ProcessSecretMessageResponse ProcessSecretMessage(ProcessSecretMessageRequest processSecretMessageRequest);
}

We constructed the Request-Response objects in the previous post.

Add the following implementation stub to the Implementations folder:

public class SecretMessageProcessingService : ISecretMessageProcessingService
{
	public ProcessSecretMessageResponse ProcessSecretMessage(ProcessSecretMessageRequest processSecretMessageRequest)
	{
		throw new NotImplementedException();
	}
}

The first step in the process will be to retrieve the AsymmetricKeyPairGenerationResult object based on the incoming message id. If you recall we have an interface called IAsymmetricKeyRepository for exactly that purpose. Add the following private field and public constructor to the service:

private readonly IAsymmetricKeyRepositoryFactory _asymmetricKeyRepositoryFactory;

public SecretMessageProcessingService(IAsymmetricKeyRepositoryFactory asymmetricKeyRepositoryFactory)
{
	if (asymmetricKeyRepositoryFactory == null) throw new ArgumentNullException("Asymmetric key repository factory.");
	_asymmetricKeyRepositoryFactory = asymmetricKeyRepositoryFactory;
}

Add the following stub to the ProcessSecretMessage method:

ProcessSecretMessageResponse response = new ProcessSecretMessageResponse();
try
{
	AsymmetricKeyPairGenerationResult asymmetricKeyInStore = _asymmetricKeyRepositoryFactory.Create().FindBy(processSecretMessageRequest.MessageId);				           _asymmetricKeyRepositoryFactory.Create().Remove(processSecretMessageRequest.MessageId);
}
catch (Exception ex)
{
        response.SecretMessageProcessResult = string.Concat("Exception during the message decryption process: ", ex.Message);
	response.Exception = ex;
}
return response;

Nothing awfully complicated up to now I hope: we retrieve the asymmetric key pair stored in the repository and remove it immediately. Recall that our implementation, i.e. InMemoryAsymmetricKeyRepository.cs throws an exception if the key is not found.

The next step is to decrypt the sender’s public key. We need to extend the IAsymmetricCryptographyService interface in the Infrastructure layer. Open IAsymmetricCryptographyService.cs and add the following method:

string DecryptCipherText(string cipherText, AsymmetricKeyPairGenerationResult keyPair);

Open RsaCryptographyService.cs and implement the new method as follows:

public string DecryptCipherText(string cipherText, XDocument keyXml)
{
	RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
	rsa.FromXmlString(keyPair.FullKeyPairXml.ToString());
	byte[] original = rsa.Decrypt(Convert.FromBase64String(cipherText), false);
	return Encoding.UTF8.GetString(original);
}

Add the following private field to SecretMessageProcessingService.cs:

private readonly IAsymmetricCryptographyService _asymmetricCryptoService;

Modify its constructor as follows:

public SecretMessageProcessingService(IAsymmetricKeyRepositoryFactory asymmetricKeyRepositoryFactory
	, IAsymmetricCryptographyService asymmetricCryptoService)
{
	if (asymmetricKeyRepositoryFactory == null) throw new ArgumentNullException("Asymmetric key repository factory.");
	if (asymmetricCryptoService == null) throw new ArgumentNullException("Asymmetric crypto service.");
	_asymmetricKeyRepositoryFactory = asymmetricKeyRepositoryFactory;
	_asymmetricCryptoService = asymmetricCryptoService;
}

Add the following line within the try-statement of the ProcessSecretMessage method:

String decryptedPublicKey = _asymmetricCryptoService.DecryptCipherText(processSecretMessageRequest.EncryptedPublicKey
	, asymmetricKeyInStore);

Now that we have the decrypted public key from the Sender we can build in the symmetric encryption service into the Receiver. Add the following interface into the Cryptography folder of the Infrastructure layer:

public interface ISymmetricEncryptionService
{
	string Decrypt(string initialisationVector, string publicKey, string cipherText);
}

Add the following private variable to SecretMessageProcessingService.cs:

private readonly ISymmetricEncryptionService _symmetricCryptoService;

…and modify its constructor as follows:

public SecretMessageProcessingService(IAsymmetricKeyRepositoryFactory asymmetricKeyRepositoryFactory
	, IAsymmetricCryptographyService asymmetricCryptoService, ISymmetricEncryptionService symmetricCryptoService)
{
	if (asymmetricKeyRepositoryFactory == null) throw new ArgumentNullException("Asymmetric key repository factory.");
	if (asymmetricCryptoService == null) throw new ArgumentNullException("Asymmetric crypto service.");
	if (symmetricCryptoService == null) throw new ArgumentException("Symmetric crypto service.");
	_asymmetricKeyRepositoryFactory = asymmetricKeyRepositoryFactory;
	_asymmetricCryptoService = asymmetricCryptoService;
	_symmetricCryptoService = symmetricCryptoService;
}

Add the following statements to the try-block of ProcessSecretMessage:

String decryptedMessage = _symmetricCryptoService.Decrypt(processSecretMessageRequest.SymmetricEncryptionArgs.InitialisationVector
	, decryptedPublicKey, processSecretMessageRequest.SymmetricEncryptionArgs.CipherText);
response.SecretMessageProcessResult = string.Concat("Message received and deciphered: ", decryptedMessage);

We let the symmetric crypto service decrypt the message using the ingredients that came from the Sender. We finally assign some message to the response. Normally you shouldn’t of course send back the decrypted message in the receipt, but in this case we want to test on the sender’s side if everything has gone well.

We’ll use the built-in RijndaelManaged class to do the symmetric encryption bit. Add the following implementation to the Cryptography folder of the Infrastructure layer:

public class RijndaelSymmetricCryptographyService : ISymmetricEncryptionService
{
	public string Decrypt(string initialisationVector, string publicKey, string cipherText)
	{
		RijndaelManaged cipherForDecryption = CreateCipherForDecryption(initialisationVector, publicKey);
		ICryptoTransform cryptoTransform = cipherForDecryption.CreateDecryptor();
		byte[] cipherTextBytes = Convert.FromBase64String(cipherText);
		byte[] plainText = cryptoTransform.TransformFinalBlock(cipherTextBytes, 0, cipherTextBytes.Length);
		return Encoding.UTF8.GetString(plainText);
	}

	private RijndaelManaged CreateCipherForDecryption(string initialisationVector, string publicKey)
	{
		RijndaelManaged cipher = new RijndaelManaged();
		cipher.KeySize = CalculateKeySize(publicKey);
		cipher.IV = RecreateInitialisationVector(initialisationVector);
		cipher.BlockSize = 128;
		cipher.Padding = PaddingMode.ISO10126;
		cipher.Mode = CipherMode.CBC;
		byte[] key = HexToByteArray(publicKey);
		cipher.Key = key;
		return cipher;
	}

	private int CalculateKeySize(string publicKey)
	{
		return (publicKey.Length / 2) * 8;
	}

	private byte[] RecreateInitialisationVector(string initialisationVector)
	{
		return Convert.FromBase64String(initialisationVector);
	}

	private byte[] HexToByteArray(string hexString)
	{
		if (0 != (hexString.Length % 2))
		{
			throw new ApplicationException("Hex string must be multiple of 2 in length");
		}
		int byteCount = hexString.Length / 2;
		byte[] byteValues = new byte[byteCount];
		for (int i = 0; i < byteCount; i++)
        	{
			byteValues[i] = Convert.ToByte(hexString.Substring(i * 2, 2), 16);
		}
		return byteValues;
	}
}

Most of this code should look familiar from the posts on symmetric encryption so I won’t go into the details here.

We need to declare in IoC.cs in the Web layer that we want to use RijndaelSymmetricCryptographyService when StructureMap stumbles upon an ISymmetricEncryptionService interface dependency. Add the following line to the Initialize block:

x.For<ISymmetricEncryptionService>().Use<RijndaelSymmetricCryptographyService>();

Start the Receiver and the Sender. Enter your message to be sent to the Receiver. I encourage you to step through the Receiver project with F11 to see how the bits and pieces are connected. If everything goes well then the Sender should get a JSON response similar to this:

{"$id":"1","SecretMessageProcessResult":"Message received and deciphered: your message","Exception":null}

That’s it really as far as a basic implementation is concerned. The system can be extended in a number of ways, e.g.:

  • Add an expiry date to the message ID from the Receiver so that the temporary RSA key pair must be consumed within a certain time limit
  • Add digital signatures so that the Sender can check the authenticity of the message from the Receiver
  • Use a one-time AES public key for the Sender as well. Even if an attacker manages to somehow figure out the public key of the Sender, it will be different when the next message is sent.

I’ll be covering SOA in a number of posts soon which will show an example of adding expiry date checking to the message chain. Regarding digital signatures you can consult this post, there should be enough to get you started. The third point is straightforward to implement: just generate a new valid AES public key when the Sender sends out the message instead of reading it from the config file.

You can view the list of posts on Security and Cryptography here.

ultimatemindsettoday

A great WordPress.com site

Elliot Balynn's Blog

A directory of wonderful thoughts

Softwarearchitektur in der Praxis

Wissenswertes zu Webentwicklung, Domain-Driven Design und Microservices

Technology Talks

on Microsoft technologies, Web, Android and others

Software Engineering

Web development

Disparate Opinions

Various tidbits

chsakell's Blog

WEB APPLICATION DEVELOPMENT TUTORIALS WITH OPEN-SOURCE PROJECTS

Guru N Guns's

OneSolution To dOTnET.

Johnny Zraiby

Measuring programming progress by lines of code is like measuring aircraft building progress by weight.

%d bloggers like this: