Encoding Decoding - NeoSOFT-Technologies/rest-dot-net-core GitHub Wiki

Why do we need the data-protection system?

Data Security Expectation is simple, my data should be secure between server round trips, even if there is a un-trusted client call. so after server round trip server should have assurance that data is untouched. In short we need a Authentic data transfer. The data-protection system is a set of cryptography APIs used by ASP.NET Core to encrypt data that must be handled by an untrusted third-party.

Encoding is the process of putting a sequence of characters such as letters, numbers and other special characters into a specialized format for efficient transmission.

Decoding is the process of converting an encoded format back into the original sequence of characters. Encoding and decoding are used in data communications and storage.

Encryption is a process of converting a plain text into an encrypted or cipher text.

Decryption is a process of converting the encrypted or cipher text into plain text.

Encryption needs a Key to encrypt data, but here, key is created and maintained by API itself, these keys are generated with the default lifespan of 90 days and stored at a secrete location. This Key is temporary, the data protection API is designed to secure short term data like Querystring, cookies etc.

NuGet Packages

  • Microsoft.AspNetCore.DataProtection.Abstractions - it is the core namespace.
  • Microsoft.AspNetCore.DataProtection.Extensions - it is used to take advantages of additional APIs that which is not belong to core packages.

Use case of Encoding

The goal is not to keep information secret, but rather to ensure that it’s able to be properly consumed. If you want to transform data temporarily then use encoding, e.g. encoding order or event Id, or viewing special characters on a web page.

Use case of Encryption

The purpose of encryption is to transform data in order to keep it secret from others. If you want to transform data permanently then use encryption, e.g. securely sending a password over the internet or storing it in database.

Code Snippet

We need to add AddDataProtection() inside ConfigureServices.

EncodingDecoding

Use of Data protection is really simple, we just need to import AspNetCore.DataProtection namesapce, and to protect the data we need to use Protect() method as shown below,

Security1

public class EventVmCustomMapper : ITypeConverter<Event, EventListVm>
   {
       private readonly IDataProtector _protector;

       public EventVmCustomMapper(IDataProtectionProvider provider)
       {
           _protector = provider.CreateProtector("");
       }
       public EventListVm Convert(Event source, EventListVm destination, ResolutionContext context)
       {
           EventListVm dest = new EventListVm()
           {
               EventId = _protector.Protect(source.EventId.ToString()),
               Name = source.Name,
               ImageUrl = source.ImageUrl,
               Date = source.Date
           };
           return dest;
       }
   }

To decode the data we need to use Unprotect() method as shown below,

Security2

public class GetEventDetailQueryHandler : IRequestHandler<GetEventDetailQuery, Response<EventDetailVm>>
    {
        private readonly IAsyncRepository<Event> _eventRepository;
        private readonly IAsyncRepository<Category> _categoryRepository;
        private readonly IMapper _mapper;

        private readonly IDataProtector _protector;
        public GetEventDetailQueryHandler(IMapper mapper, IAsyncRepository<Event> eventRepository, 
            IAsyncRepository<Category> categoryRepository, IDataProtectionProvider provider)
        {
            _mapper = mapper;
            _eventRepository = eventRepository;
            _categoryRepository = categoryRepository;
            _protector = provider.CreateProtector("");
        }

        public async Task<Response<EventDetailVm>> Handle(GetEventDetailQuery request, CancellationToken cancellationToken)
        {           
            string id = _protector.Unprotect(request.Id);

            var @event = await _eventRepository.GetByIdAsync(new Guid(id));
            var eventDetailDto = _mapper.Map<EventDetailVm>(@event);

            var category = await _categoryRepository.GetByIdAsync(@event.CategoryId);

            if (category == null)   
            {
                throw new NotFoundException(nameof(Event), request.Id);
            }
            eventDetailDto.Category = _mapper.Map<CategoryDto>(category);

            var response = new Response<EventDetailVm>(eventDetailDto);         
            return response;
        }
    }

We need to add EncryptionDecryption helper class in our project for encryption decryption use as below,

public static class EncryptionDecryption
    {
        //This function for Encryption which accepts the plain text and Key and return Encrypted string
        public static string EncryptString(string clearText)
        {
            string EncryptionKey = Environment.GetEnvironmentVariable("EncryptionDeckryptionKey")?.ToString().Length > 0  ? Environment.GetEnvironmentVariable("EncryptionDeckryptionKey") : "";
            byte[] clearBytes = Encoding.Unicode.GetBytes(clearText);
            using (Aes encryptor = Aes.Create())
            {
                var salt = Encoding.UTF8.GetBytes("0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76");
                Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes(EncryptionKey, salt);
                encryptor.Key = pdb.GetBytes(32);
                encryptor.IV = pdb.GetBytes(16);
                using (MemoryStream ms = new MemoryStream())
                {
                    using (CryptoStream cs = new CryptoStream(ms, encryptor.CreateEncryptor(), CryptoStreamMode.Write))
                    {
                        cs.Write(clearBytes, 0, clearBytes.Length);
                        cs.Close();
                    }
                    clearText = Convert.ToBase64String(ms.ToArray());
                }
            }
            return clearText;
        }


        //This function for Decryption which accepts Encrypted string and Key and return plain text string
        public static string DecryptString(string cipherText)
        {
            string EncryptionKey = Environment.GetEnvironmentVariable("EncryptionDeckryptionKey")?.ToString().Length > 0 ? Environment.GetEnvironmentVariable("EncryptionDeckryptionKey") : "";
            byte[] cipherBytes = Convert.FromBase64String(cipherText);
            using (Aes encryptor = Aes.Create())
            {
                var salt = Encoding.UTF8.GetBytes("0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76");
                Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes(EncryptionKey, salt);
                encryptor.Key = pdb.GetBytes(32);
                encryptor.IV = pdb.GetBytes(16);
                using (MemoryStream ms = new MemoryStream())
                {
                    using (CryptoStream cs = new CryptoStream(ms, encryptor.CreateDecryptor(), CryptoStreamMode.Write))
                    {
                        cs.Write(cipherBytes, 0, cipherBytes.Length);
                        cs.Close();
                    }
                    cipherText = Encoding.Unicode.GetString(ms.ToArray());
                }
            }
            return cipherText;
        }
    }

The EnvironmentVariable which defines EncryptionKey can be changed. To do so right click on Project API and then click on Properties, then go to Debug section and the variables are as shown below,

Security3

⚠️ **GitHub.com Fallback** ⚠️