Encrypting and decrypting data

There are multiple encryption algorithms you can choose from in .NET Core. Some algorithms are implemented by the operating system and their names are suffixed with the CryptoServiceProvider class, some are implemented entirely in .NET, some use symmetric keys, and some use asymmetric keys.

Tip

Best Practice

Choose AES for symmetric encryption and RSA for asymmetric encryption.

Encrypting symmetrically with AES

To make it easier to reuse your protection code in the future, we will create a static class named Protector in its own class library.

Using Visual Studio 2017

In Visual Studio 2017, press Ctrl + Shift + N or navigate to File | New | Project....

In the New Project dialog, in the Installed | Templates list, expand Visual C# and select .NET Standard. In the list at the center, select Class Library (.NET Standard), type the name Ch11_CryptographyLib, change the location to C:Code, type the solution name as Chapter11, and then click on OK. Rename Class1.cs to Protector.cs.

In Visual Studio 2017, add a new console application project named Ch11_EncryptionApp.

Note

Make sure that you add Console App (.NET Core) and not Class Library (.NET Standard)!

Set your solution's startup project as the current selection.

In Solution Explorer, in the Ch11_EncryptionApp project, right-click on Dependencies and choose Add Reference..., select the Ch11_CryptographyLib project, and then click on OK.

Using Visual Studio Code

In macOS, in the Code folder, create a folder named Chapter11, with two subfolders named Ch11_CryptographyLib and Ch11_EncryptionApp.

In Visual Studio Code, open the folder named Ch11_CryptographyLib.

In the Integrated Terminal, enter the following command:

dotnet new classlib

Open the folder named Ch11_EncryptionApp.

In the Integrated Terminal, enter the following command:

dotnet new console

Open the folder named Chapter11.

In the Explorer window, expand Ch11_CryptographyLib and rename the Class1.cs file to Protector.cs.

In the Ch11_EncryptionApp project folder, open the file named Ch11_EncryptionApp.csproj, and add a package reference to the Ch11_CryptographyLib library, as shown highlighted in the following markup:

    <Project Sdk="Microsoft.NET.Sdk"> 
 
      <PropertyGroup> 
        <OutputType>Exe</OutputType> 
        <TargetFramework>netcoreapp1.1</TargetFramework> 
      </PropertyGroup> 
 
      <ItemGroup> 
        <ProjectReference Include="..Ch11_CryptographyLibCh11_CryptographyLib.csproj"
        /> 
      </ItemGroup> 
 
    </Project> 

In the Integrated Terminal, enter the following commands:

cd Ch11_EncryptionApp
dotnet restore
dotnet build

Creating the Protector class

In both Visual Studio 2017 and Visual Studio Code, open the Protector.cs file and change its contents to look like this:

    using System; 
    using System.Collections.Generic; 
    using System.IO; 
    using System.Security.Cryptography; 
    using System.Text; 
    using System.Xml.Linq; 
 
    namespace Packt.CS7 
    { 
      public static class Protector 
      { 
        // salt size must be at least 8 bytes, we will use 16 bytes 
        private static readonly byte[] salt =  
          Encoding.Unicode.GetBytes("7BANANAS"); 
 
        // iterations must be at least 1000, we will use 2000 
        private static readonly int iterations = 2000; 
 
        public static string Encrypt( 
          string plainText, string password) 
        { 
          byte[] plainBytes = Encoding.Unicode.GetBytes(plainText); 
          var aes = Aes.Create(); 
          var pbkdf2 = new Rfc2898DeriveBytes( 
            password, salt, iterations); 
          aes.Key = pbkdf2.GetBytes(32); // set a 256-bit key 
          aes.IV = pbkdf2.GetBytes(16); // set a 128-bit IV 
          var ms = new MemoryStream(); 
          using (var cs = new CryptoStream( 
            ms, aes.CreateEncryptor(), CryptoStreamMode.Write)) 
          { 
            cs.Write(plainBytes, 0, plainBytes.Length); 
          } 
          return Convert.ToBase64String(ms.ToArray()); 
        } 
 
        public static string Decrypt( 
          string cryptoText, string password) 
        { 
          byte[] cryptoBytes = Convert.FromBase64String(cryptoText); 
          var aes = Aes.Create(); 
          var pbkdf2 = new Rfc2898DeriveBytes( 
            password, salt, iterations); 
          aes.Key = pbkdf2.GetBytes(32); 
          aes.IV = pbkdf2.GetBytes(16); 
          var ms = new MemoryStream(); 
          using (var cs = new CryptoStream( 
            ms, aes.CreateDecryptor(), CryptoStreamMode.Write)) 
          { 
            cs.Write(cryptoBytes, 0, cryptoBytes.Length); 
          } 
          return Encoding.Unicode.GetString(ms.ToArray()); 
        } 
      } 
    } 

Note the following points:

  • We used double the recommended salt size and iteration count
  • Although the salt and iteration count can be hardcoded, the password must be passed at runtime when calling Encrypt and Decrypt
  • We use a temporary MemoryStream type to store the results of encrypting and decrypting and then call ToArray to turn the stream into a byte array
  • We convert the encrypted byte arrays to and from a Base64 encoding to make them easier to read

Tip

Good Practice

Never hardcode a password in your source code because, even after compilation, the password can be read in the assembly by using disassembler tools.

In the Ch11_EncryptionApp project, open the Program.cs file and then import the following namespace and type:

    using Packt.CS7; 
    using static System.Console; 

In the Main method, add the following statements to prompt the user for a message and a password and then encrypt and decrypt:

    Write("Enter a message that you want to encrypt: "); 
    string message = ReadLine(); 
    Write("Enter a password: "); 
    string password = ReadLine(); 
    string cryptoText = Protector.Encrypt(message, password); 
    WriteLine($"Encrypted text: {cryptoText}"); 
    Write("Enter the password: "); 
    string password2 = ReadLine(); 
    try 
    { 
      string clearText = Protector.Decrypt(cryptoText, password2); 
      WriteLine($"Decrypted text: {clearText}"); 
    } 
    catch 
    { 
      WriteLine( 
        "Enable to decrypt because you entered the wrong password!"); 
    } 

Run the console application.

Note

In Visual Studio 2017, press Ctrl + F5. In Visual Studio Code, in the Integrated Terminal, enter the command: dotnet run

Try entering a message and password, and view the output:

Enter a message that you want to encrypt: Hello Bob
Enter a password: secret
Encrypted text: pV5qPDf1CCZmGzUMH2gapFSkn573lg7tMj5ajice3cQ=
Enter the password: secret
Decrypted text: Hello Bob

Rerun the application and try entering a message and password, but this time enter the password incorrectly after encrypting and view the output:

Enter a message that you want to encrypt: Hello Bob
Enter a password: secret
Encrypted text: pV5qPDf1CCZmGzUMH2gapFSkn573lg7tMj5ajice3cQ=
Enter the password: 123456
Enable to decrypt because you entered the wrong password!
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.219.198.159