Cryptography with Practical Examples in .Net Core
Tags: csharp, cryptography, dotnet
Published: 2020-06-08 09:57:19

This week at [Stratiteq](https://dev.to/stratiteq), on our weekly tech talk we spoke about cryptography and concepts behind it with practical examples in .Net Core.

Cryptography (from Ancient Greek, *cruptos* = "hidden", *graphein* = "to write") is the study of techniques for preventing third parties from reading or manipulating private messages. Cryptography has been around for a long time and it was mostly used for military purposes. Technology behind it did not change much over time and "boom" happened in second part of 20th century, so nowadays we can find cryptography everywhere:
 - Secure network communication (TLS/SSL)
 - Authentication and digital signatures
 - Contactless
 - Block chain technology
 - Bank / credit cards
 - Hard disk encryption
 - GSM
 - E-mail, FTP, biometry, etc...

Cryptography is not just used in the technologies listed above, we can see many industry leaders talking about it, we see it disrupting industries and we can for sure say it is in some way changing the world around us.

Even it sounds complicated, it more or less boils down into three simple concepts. We'll not go into math and science behind it, but we are going to explain the concepts and go through examples which you can try by yourself.

Those three main concepts are:
 - Hashing
 - Encryption
 - Signatures

# Hashing
**Hashing** can be simply explained as translation from input text into resulting text of fixed size by use of the algorithm.

![Hashing](https://dev-to-uploads.s3.amazonaws.com/i/zt8zdxwp6tdgnzinom3j.png)

As you can see in above examples with just a slight change of input text, result will be completely different.

Let's take a look at an example in .Net Core with use of SHA-256 algorithm. For following examples we'll have to use System.Security.Cryptography namespace, you can find more info about it [here](https://docs.microsoft.com/en-us/dotnet/api/system.security.cryptography?view=dotnet-plat-ext-3.1).

```csharp
using System.Security.Cryptography;
```
In following function we are hashing texts to demonstrate how hashing works, and how results change if we just make a slight change to the text.
```csharp
        internal static void CryptographicHashFunctionDemo()
        {
            Console.WriteLine("***** Cryptographic hash demo *****");

            foreach (var message in new[] {
                "Fox",
                "The red fox jumps over the blue dog",
                "The red fox jumps ouer the blue dog",
                "The red fox jumps oevr the blue dog",
                "The red fox jumps oer the blue dog"})
            {
                Console.WriteLine($"{ message } => { CryptographicHash.ComputeHash(message) }");
            }
            
            Console.Write(Environment.NewLine);
        }
```
If we take a closer look at the ComputeHash we can see texts are encrypted with SHA-256 algorithm.
```csharp
        internal static string ComputeHash(string message)
        {
            using var sha256 = SHA256.Create();
            var hashedBytes = sha256.ComputeHash(Encoding.UTF8.GetBytes(message));
            return hashedBytes.ToHex();
        }
```
By running the code, you'll get following results.

![Console](https://dev-to-uploads.s3.amazonaws.com/i/28z78sax8cjh6xf18r7v.png)

# Encryption
**Encryption** is the process of sending information to a recipient that can't be interpreted unless having access to a key. Encryption always consist of two parts, an algorithm and a key.

Encryption can be symmetric and asymmetric. In symmetric encryption same key is used for encryption and decryption, while in asymmetric different keys are in use: public key and private key.

![symmetric-asymmetric](https://dev-to-uploads.s3.amazonaws.com/i/5qelfivmvfreo0uarbss.png)

**Symmetric encryption** can be seen in the following example. We create a key, encrypt message using the key and decrypt message using the same key.
```csharp
        internal static void SymmetricEncryptionDemo()
        {
            Console.WriteLine("***** Symmetric encryption demo *****");

            var unencryptedMessage = "To be or not to be, that is the question, whether tis nobler in the...";
            Console.WriteLine("Unencrypted message: " + unencryptedMessage);

            // 1. Create a key (shared key between sender and reciever).
            byte[] key, iv;
            using (Aes aesAlg = Aes.Create())
            {
                key = aesAlg.Key;
                iv = aesAlg.IV;
            }

            // 2. Sender: Encrypt message using key
            var encryptedMessage = SymmetricEncryption.Encrypt(unencryptedMessage, key, iv);
            Console.WriteLine("Sending encrypted message: " + encryptedMessage.ToHex());

            // 3. Receiver: Decrypt message using same key
            var decryptedMessage = SymmetricEncryption.Decrypt(encryptedMessage, key, iv);
            Console.WriteLine("Recieved and decrypted message: " + decryptedMessage);
            
            Console.Write(Environment.NewLine);
        }
```
In SymmetricEncryption class we have Encrypt and Decrypt defined as follows. You can notice we are using AES algorithm.
```csharp
        internal static byte[] Encrypt(string message, byte[] key, byte[] iv)
        {
            using var aesAlg = Aes.Create();
            aesAlg.Key = key;
            aesAlg.IV = iv;

            var encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);

            using var ms = new MemoryStream();
            using var cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write);
            using (var sw = new StreamWriter(cs))
            { 
                sw.Write(message); // Write all data to the stream.
            }
            return ms.ToArray();
        }

        internal static string Decrypt(byte[] cipherText, byte[] key, byte[] iv)
        {
            using var aesAlg = Aes.Create();
            aesAlg.Key = key;
            aesAlg.IV = iv;

            var decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);

            using var ms = new MemoryStream(cipherText);
            using var cs = new CryptoStream(ms, decryptor, CryptoStreamMode.Read);
            using var sr = new StreamReader(cs);
            return sr.ReadToEnd();
        }
```
If you run the code, you'll get following result.

![Console 2](https://dev-to-uploads.s3.amazonaws.com/i/2n4uavp06haggjbk3cu8.png)

**Asymmetric encryption** has few common algorithms that are in the use:
 - RSA; by Ron Rivest, Adi Shamir and Len Adleman; from 1977
 - EC (Elliptic Curve); Neal Koblitz and Victor S. Miller; from 1985

These algorithms can be used for encryption and decryption, as well as digital signatures.

In another example we can see asymmetric encryption in action using the RSA algorithm.
```csharp
        internal static void AsymmetricEncryptionDemo()
        {
            Console.WriteLine("***** Asymmetric encryption demo *****");

            var unencryptedMessage = "To be or not to be, that is the question, whether tis nobler in the...";
            Console.WriteLine("Unencrypted message: " + unencryptedMessage);

            // 1. Create a public / private key pair.
            RSAParameters privateAndPublicKeys, publicKeyOnly;
            using (var rsaAlg = RSA.Create())
            {
                privateAndPublicKeys = rsaAlg.ExportParameters(includePrivateParameters: true);
                publicKeyOnly = rsaAlg.ExportParameters(includePrivateParameters: false);
            }

            // 2. Sender: Encrypt message using public key
            var encryptedMessage = AsymmetricEncryption.Encrypt(unencryptedMessage, publicKeyOnly);
            Console.WriteLine("Sending encrypted message: " + encryptedMessage.ToHex());

            // 3. Receiver: Decrypt message using private key
            var decryptedMessage = AsymmetricEncryption.Decrypt(encryptedMessage, privateAndPublicKeys);
            Console.WriteLine("Recieved and decrypted message: " + decryptedMessage);
            
            Console.Write(Environment.NewLine);
        }
```
As you can see, in the AsymmetricEncryptionDemo function we create a public and a private key pair, we encrypt the message using the public key and we decrypt message using the private key.

Encrypt and Decrypt are defined as follows and we are using RSA algorithm.
```csharp
        internal static byte[] Encrypt(string message, RSAParameters rsaParameters)
        {
            using var rsaAlg = RSA.Create(rsaParameters);
            return rsaAlg.Encrypt(Encoding.UTF8.GetBytes(message), RSAEncryptionPadding.Pkcs1);
        }

        internal static string Decrypt(byte[] cipherText, RSAParameters rsaParameters)
        {
            using var rsaAlg = RSA.Create(rsaParameters);
            var decryptedMessage = rsaAlg.Decrypt(cipherText, RSAEncryptionPadding.Pkcs1);
            return Encoding.UTF8.GetString(decryptedMessage);
        }
```
Result in the console looks as follows.

![Console 3](https://dev-to-uploads.s3.amazonaws.com/i/xqut55r79eypvg9s0nil.png)

# Digital signatures
**Digital signatures** are built on top of asymmetric cryptography. They are used to send information to recipients who can verify that the information was sent from a trusted sender, using a public key.

Let's take a look at the example of digital signature:
```csharp
        internal static void MessageSignatureDemo()
        {
            Console.WriteLine("***** Message signature demo *****");

            var message = "To be or not to be, that is the question, whether tis nobler in the...";
            Console.WriteLine("Message to be verified: " + message);

            // 1. Create a public / private key pair.
            RSAParameters privateAndPublicKeys, publicKeyOnly;
            using (var rsaAlg = RSA.Create())
            {
                privateAndPublicKeys = rsaAlg.ExportParameters(includePrivateParameters: true);
                publicKeyOnly = rsaAlg.ExportParameters(includePrivateParameters: false);
            }

            // 2. Sender: Sign message using private key
            var signature = AsymmetricEncryption.Sign(message, privateAndPublicKeys);
            Console.WriteLine("Message signature: " + signature.ToHex());

            // 3. Receiver: Verify message authenticity using public key
            var isTampered = AsymmetricEncryption.Verify(message, signature, publicKeyOnly);
            Console.WriteLine("Message is untampered: " + isTampered.ToString());

            Console.Write(Environment.NewLine);
        }
```
In the MessageSignatureDemo function we create a public and a private key pair, we sign the message with the private key and we verify the message for authenticity using public key.

Sign and Verify works in the following way, we're using the RSA algorithm.
```csharp
        internal static byte[] Sign(string message, RSAParameters rsaParameters)
        {
            using var rsaAlg = RSA.Create(rsaParameters);
            return rsaAlg.SignData(Encoding.UTF8.GetBytes(message), HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
        }

        internal static bool Verify(string message, byte[] signature, RSAParameters rsaParameters)
        {
            using var rsaAlg = RSA.Create(rsaParameters);
            return rsaAlg.VerifyData(Encoding.UTF8.GetBytes(message), signature, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
        }
```
Console will display following result for running digital signature example.

![Console 4](https://dev-to-uploads.s3.amazonaws.com/i/atkq03r2gymwlmcwzfiq.png)

Project and all code from this blog post is available at the GitHub [here](https://github.com/stratiteq/techcomp-crypto). Thanks for reading!