Encrypt Payload Using Angular 11 And ASP.NET Core

Introduction

  • I have covered everything more useful for security in this essay.
  • I’ll start by explaining how to use Angular 11 (the front end) and ASP.NET CORE to encrypt and decrypt the entire payload or any given id (API).
  • Both Angular and ASP.NET CORE have code that uses the AES256 algorithm. Using middleware that I will walk you through, you can access payload or ids in ASP.NET CORE from the angular side by utilising interceptor, sending the payload or id with encryption, and using the same methodology.
  • You must first develop a project. If not, design and complete any CRUD operations as well as any GET and POST-based functionality; otherwise, you can include them into your existing project.

Step 1

Install the crypto js using the npm terminal. Use the below command to install the crypto js:

npm i crypto-js
  • I have used 4.1.1 version. You can use according to your angular version.
  • Once we’ve installed Crypto Js, we have to create one service to encrypt the payload or parameter.

Step 2

  • Build the AES256 payload encryption and decryption service.
  • To utilise the same key and IV on the asp.net code side for decryption, we must first acquire a unique 16-number code for encryption purposes.
  • I’m using the same ID for each of these. You can configure them differently, but make sure you decode the code with the same key and IV.

environment.EncryptKey = 1203199320052021

environment.EncryptIV = 1203199320052021

Here I have created a service and given it the name encrypt-decrypt.service.ts.

import { Injectable } from '@angular/core';
import * as CryptoJS from 'crypto-js';
import { environment } from 'src/environments/environment';

@Injectable({
    providedIn: 'root'
})
export class EncryptDecryptService {
    private key = CryptoJS.enc.Utf8.parse(environment.EncryptKey);
    private iv = CryptoJS.enc.Utf8.parse(environment.EncryptIV);
    constructor() {}
    // Methods for the encrypt and decrypt Using AES
    encryptUsingAES256(text): any {
        var encrypted = CryptoJS.AES.encrypt(CryptoJS.enc.Utf8.parse(text), this.key, {
            keySize: 128 / 8,
            iv: this.iv,
            mode: CryptoJS.mode.CBC,
            padding: CryptoJS.pad.Pkcs7
        });
        return encrypted.toString();
    }
    decryptUsingAES256(decString) {
        var decrypted = CryptoJS.AES.decrypt(decString, this.key, {
            keySize: 128 / 8,
            iv: this.iv,
            mode: CryptoJS.mode.CBC,
            padding: CryptoJS.pad.Pkcs7
        });
        return decrypted.toString(CryptoJS.enc.Utf8);
    }
}
  • HTTP Interceptors is a special type of angular service that we can implement. It’s used to apply custom logic to the central point between the client-side and server-side outgoing/incoming HTTP request and response. Keep in mind that the interceptor wants only HTTP requests.
  • Let’s create an interceptor.

Step 3

  • Create the interceptor file to generate encrypted payload before passing it into API service call.
  • I created interceptor with encrypt-decrypt-interceptor.ts name.

See the below code of interceptor method:

import { Injectable } from '@angular/core';
import { HttpInterceptor, HttpRequest, HttpHandler, HttpEvent } from '@angular/common/http';
import { EncryptDecryptService } from './services/encrypt-decrypt.service';
import { Observable } from 'rxjs/Observable';
import { environment } from 'src/environments/environment';

@Injectable()
export class EncryptDecryptAuthInterceptor implements HttpInterceptor {
    constructor(private encryptDecryptService: EncryptDecryptService, ) {}
    // If you want to some exclude api call from Encryption then add here like that.
    // environment.basUrl is your API URL
    ExcludeURLList = [
        environment.baseUrl + "/api/Common/commonFileuploaddata",
        environment.baseUrl + "/api/Users/UploadProfilePicture",
        environment.baseUrl + "/api/Common/downloadattachedfile"
    ];
    intercept(req: HttpRequest < any > , next: HttpHandler): Observable < HttpEvent < any >> {
        let exludeFound = this.ExcludeURLList.filter(element => {
            return req.url.includes(element)
        });
        // We have Encrypt the GET and POST call before pass payload to API
        if (!(exludeFound && exludeFound.length > 0)) {
            if (req.method == "GET") {
                if (req.url.indexOf("?") > 0) {
                    let encriptURL = req.url.substr(0, req.url.indexOf("?") + 1) + this.encryptDecryptService.encryptUsingAES256(req.url.substr(req.url.indexOf("?") + 1, req.url.length));
                    const cloneReq = req.clone({
                        url: encriptURL
                    });
                    return next.handle(cloneReq);
                }
                return next.handle(req);
            } else if (req.method == "POST") {
                if (req.body || req.body.length > 0) {
                    const cloneReq = req.clone({
                        body: this.encryptDecryptService.encryptUsingAES256(req.body)
                    });
                    return next.handle(cloneReq);
                }
                let data = req.body as FormData;
                return next.handle(req);
            }
        }
        return next.handle(req);
    }
}
  • I want to make it clear that adding an API URL to the ExcludeURLList, as displayed in Interceptor, will allow you to exclude API requests from encryption. Several methods or API calls in our app don’t need to be encrypted. So that we may handle things our way. Let’s say I specify here that some API calls disallow lists from uploading related picture lists. Therefore encryption is not required while uploading photos. I thus put it to the exclusion list.
  • Now need to configure it into a module file so that whenever we call the API it will call the interceptor before API and encrypt the payload. Then it will pass into API (GET or POST).

Step 4: Configure interceptor in app.module.ts file

  • First, import the inceptor that we created (encrypt-decrypt-interceptor.ts) and configure Interceptor into provider.
  • See the below sample app.module.ts:
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { EncryptDecryptAuthInterceptor } from './encrypt-decrypt-interceptor';
@NgModule({
    imports: [],
    declarations: [
        AppComponent,
    ],
    providers: [{
            provide: 'BASE_URL',
            useFactory: getBaseUrl
        }, {
            provide: ErrorHandler,
            useClass: AppErrorHandler
        }, {
            provide: HTTP_INTERCEPTORS,
            useClass: EncryptDecryptAuthInterceptor,
            multi: true
        },
        CommonService,
    ],
    bootstrap: [AppComponent],
    entryComponents: [],
    exports: [],
    schemas: [CUSTOM_ELEMENTS_SCHEMA]
})
export class AppModule {}
export function getBaseUrl() {
    return document.getElementsByTagName('base')[0].href;
}
  • Now, the front-end Angular side code is done using all the above steps to encrypt the payload and parameter so that no one can see the original payload or parameter.

ASP.NET Core Code

  • In order to decrypt the payload before invoking the Controller Action function, I have made one middleware helper. The biggest advantage of this is that we haven’t had to write a lot of code to cover everything. To call middleware on each ASP.NET CORE request, all you need to do is utilise middleware and call it from the Startup.cs file.
  • With ASP.Net Core, we may set an exclusion list similarly to Angular.
  • Software components known as middleware are put together into an application pipeline to handle requests and answers. Each component in the pipeline decides whether to move the request on to the next component in the pipeline and has some control over what happens both before and after the next component is called.

First, we need to create a middleware helper to encrypt-decrypt the payload and parameter, which is passing from angular.

Create a middleware helper name EncryptionMiddleware.cs and copy and paste the below code.

using FC_API.Data.Access;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Options;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
namespace Rajesh_API.Helpers {
    public class EncryptionMiddleware {
        private readonly RequestDelegate _next;
        private readonly AppSettings _appSettings;
        public EncryptionMiddleware(RequestDelegate next, IOptions < AppSettings > appSettings) {
            _next = next;
            _appSettings = appSettings.Value;
        }
        // Whenever we call any action method then call this before call the action method
        public async Task Invoke(HttpContext httpContext) {
            List < string > excludeURL = GetExcludeURLList();
            if (!excludeURL.Contains(httpContext.Request.Path.Value)) {
                httpContext.Request.Body = DecryptStream(httpContext.Request.Body);
                if (httpContext.Request.QueryString.HasValue) {
                    string decryptedString = DecryptString(httpContext.Request.QueryString.Value.Substring(1));
                    httpContext.Request.QueryString = new QueryString($ "?{decryptedString}");
                }
            }
            await _next(httpContext);
        }
        // This function is not needed but if we want anything to encrypt then we can use
        private CryptoStream EncryptStream(Stream responseStream) {
            Aes aes = GetEncryptionAlgorithm();
            ToBase64Transform base64Transform = new ToBase64Transform();
            CryptoStream base64EncodedStream = new CryptoStream(responseStream, base64Transform, CryptoStreamMode.Write);
            ICryptoTransform encryptor = aes.CreateEncryptor(aes.Key, aes.IV);
            CryptoStream cryptoStream = new CryptoStream(base64EncodedStream, encryptor, CryptoStreamMode.Write);
            return cryptoStream;
        }
        static byte[] Encrypt(string plainText) {
            byte[] encrypted;
            using(AesManaged aes = new AesManaged()) {
                ICryptoTransform encryptor = aes.CreateEncryptor(aes.Key, aes.IV);
                using(MemoryStream ms = new MemoryStream()) {
                    using(CryptoStream cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write)) {
                        using(StreamWriter sw = new StreamWriter(cs))
                        sw.Write(plainText);
                        encrypted = ms.ToArray();
                    }
                }
            }
            return encrypted;
        }
        // This are main functions that we decrypt the payload and  parameter which we pass from the angular service.
        private Stream DecryptStream(Stream cipherStream) {
            Aes aes = GetEncryptionAlgorithm();
            FromBase64Transform base64Transform = new FromBase64Transform(FromBase64TransformMode.IgnoreWhiteSpaces);
            CryptoStream base64DecodedStream = new CryptoStream(cipherStream, base64Transform, CryptoStreamMode.Read);
            ICryptoTransform decryptor = aes.CreateDecryptor(aes.Key, aes.IV);
            CryptoStream decryptedStream = new CryptoStream(base64DecodedStream, decryptor, CryptoStreamMode.Read);
            return decryptedStream;
        }
        private string DecryptString(string cipherText) {
            Aes aes = GetEncryptionAlgorithm();
            byte[] buffer = Convert.FromBase64String(cipherText);
            MemoryStream memoryStream = new MemoryStream(buffer);
            ICryptoTransform decryptor = aes.CreateDecryptor(aes.Key, aes.IV);
            CryptoStream cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read);
            StreamReader streamReader = new StreamReader(cryptoStream);
            return streamReader.ReadToEnd();
        }
        // We have to use same KEY and IV as we use for encryption in angular side.
        // _appSettings.EncryptKey= 1203199320052021
        // _appSettings.EncryptIV = 1203199320052021
        private Aes GetEncryptionAlgorithm() {
            Aes aes = Aes.Create();
            var secret_key = Encoding.UTF8.GetBytes(_appSettings.EncryptKey);
            var initialization_vector = Encoding.UTF8.GetBytes(_appSettings.EncryptIV);
            aes.Key = secret_key;
            aes.IV = initialization_vector;
            return aes;
        }
        // This are excluded URL from encrypt- decrypt that already we added in angular side and as well as in ASP.NET CORE side.
        private List < string > GetExcludeURLList() {
            List < string > excludeURL = new List < string > ();
            excludeURL.Add("/api/Common/commonFileuploaddata");
            excludeURL.Add("/api/Users/UploadProfilePicture");
            excludeURL.Add("/api/Common/downloadattachedfile");
            return excludeURL;
        }
    }
}

Now we need this middleware call from Startup.cs file. See the below screenshot:

  • Here, all the code is complete. Now you can run the project and see the result. Make sure to use the same 16-digit code for both encryption and decryption. If you want to add a long digit unique code then you can, but make sure its basis is of the AES256 algorithm rule. This means 128 bit(16 digits), 192 bit (24 digits), or 256 bit(32 digits) encryption, Here I have used 128-bit encryption.

Submit a Comment

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

Subscribe

Select Categories