React – Encryption with Crypto.js & Material UI Table

Photo by cottonbro from Pexels

Overview

The is an example of using encryption with Crypto.js in React. The URL parameters will be encrypted with AES and a SHA 256 Hash. The application will have a detail page where it will decode the ID parameter and then get and check the SHA 256 hash string generated from the user’s ID, first, and last names.

To learn more about crypto-js please visit the GitHub repository with documentation here.

Warning: This example uses Material UI.

Source Files For This Article

Get Source Code

The URL will have an encrypted record ID and a hash shown in Fig 1.

Fig 1

Application in motion.

Prerequisites

Material UIVersion 4

Note: Version 5 was released during the development of this article.

For version 4 documentation click here
For the current version documentation click here
All documentation for all versions here

npm install @material-ui/core@4.12.3 @material-ui/icons@4.11.2 

React Router

Install react-dom-router. Documentation for the router here.

npm i react-router-dom

Crypto

This is an example of how to encrypt and decrypt an id sent over as a router parameter.

Install Crytpo.js. Documentation for Crypto.js here.

npm i crypto-js

This example the functions will be accessible globally,

Router would look like the following:

<Route exact path=”/event/:eventId” render={(props) => <ParentLayout eventId={props} /> } /> 

AES Encryption

Create a Crypto-Helper.js file in the root of the application.

Use encodeURIComponent() and decodeURIComponent () to remove/replace the slashes “/” so the router doesn’t confuse a value after a slash as a parameter. A dynamic value such as a date can be used to for a better encryption key. Ideally, The secret key would come from an API or if you are using a framework like Next.js that supports Server Side Rendering then a secret key could be generated and stored in a more secure location.

import hmacSHA512 from 'crypto-js/hmac-sha512';
import Base64 from 'crypto-js/enc-base64';
var CryptoJS = require("crypto-js");


const dynamicValue = '12/12/2021'; // Could use a date or something dynamic

export function AESEncrypt(pureText) {    
    const privateKey=`${dynamicValue} secret key 123`;    
    var ciphertext = encodeURIComponent(CryptoJS.AES.encrypt(JSON.stringify(pureText), privateKey).toString());    
    return ciphertext;
}

export function AESDecrypt(encryptedText) {  
    const privateKey=`${dynamicValue} secret key 123`;    
    var bytes  = CryptoJS.AES.decrypt(decodeURIComponent(encryptedText), privateKey);
    var decryptedData = JSON.parse(bytes.toString(CryptoJS.enc.Utf8));    
    return decryptedData;
}

export function Sha256Hash(id, first, last) {    
    const pureText = `${first}-${id}-${last}`;
    const privateKey=`${dynamicValue} secret key 123`;    
    var hash = encodeURIComponent(Base64.stringify(hmacSHA512(pureText, privateKey)));    
    return hash;
}

Table – Encrypt the ID

Encrypt the id with AES Encryption and create a Hash value with SHA 256.

import { Sha256Hash,AESEncrypt } from '../Global/Crypto-Helper';
...
${AESEncrypt(row.id)}
...
{Sha256Hash(row.id, row.first, row.last)}

The entire page with Material Table.

import React, { Component } from 'react';
import Grid from '@material-ui/core/Grid';
import Table from '@material-ui/core/Table';
import TableBody from '@material-ui/core/TableBody';
import TableCell from '@material-ui/core/TableCell';
import TableContainer from '@material-ui/core/TableContainer';
import TableHead from '@material-ui/core/TableHead';
import TableRow from '@material-ui/core/TableRow';
import Paper from '@material-ui/core/Paper';
import Button from '@material-ui/core/Button';
import { Sha256Hash,AESEncrypt } from '../Global/Crypto-Helper';
import data from '../Data/users.json';
import { Link } from 'react-router-dom';

export default class DataTable extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            users: data
        };        
    }
    
    render() {
        console.log(data)
        return (
            <div className="container">
                <Grid container>
                    <Grid xs={1}></Grid>
                    <Grid xs={10}>
                        <TableContainer component={Paper}>
                            <Table aria-label="customized table">
                                <TableHead>
                                <TableRow>
                                    <TableCell >Action</TableCell>
                                    <TableCell >ID</TableCell>
                                    <TableCell >Hash (first name - id - last name)</TableCell>
                                    <TableCell >Name</TableCell>
                                    <TableCell  align="right">Email</TableCell>                            
                                </TableRow>
                                </TableHead>
                                <TableBody>
                                {this.state.users.map((row, i) => (
                                    
                                    <TableRow  key={i}>
                                        <TableCell  align="left"><Button variant="outlined" color="primary" component={Link} to={`details/${AESEncrypt(row.id)}/${Sha256Hash(row.id, row.first, row.last)}`}>View</Button> </TableCell>
                                        <TableCell  component="th" scope="row">
                                        {row.id}
                                        </TableCell>                            

                                        <TableCell  component="th" scope="row">
                                        {Sha256Hash(row.id, row.first, row.last)}
                                        </TableCell>                            

                                        <TableCell  component="th" scope="row">
                                        {row.first} {row.last}
                                        </TableCell>                            
                                        <TableCell  align="right">{row.email}</TableCell>
                                    </TableRow>
                                ))}
                                </TableBody>
                            </Table>
                        </TableContainer>
                    </Grid>
                    </Grid>
            </div>
        );
    }
}

Receiving Detail Component

Decrypting and Checking the Hash

Using the AESDecrypt and Sha256Hash functions created in the Crypto-Helper.js file. First decrypt the ID to lookup the user so the Hash can be generated and used to check the one in the 2nd parameter in the URL.

import { AESDecrypt, Sha256Hash } from '../Global/Crypto-Helper';
...

const decryptedId = AESDecrypt(id);    

var rec = users.map(item => {
    if(item.id === decryptedId) {
        console.log(item);                    
        usr=item;
    }
}); 

All together with the Material Grid and Typography tags to show the ID, Name, Hash from the parameter and the hash generated with the user information.

import React, { useState } from 'react'
import { AESDecrypt, Sha256Hash } from '../Global/Crypto-Helper';
import { useParams } from "react-router-dom";
import users from '../Data/users.json';
import Typography from '@material-ui/core/Typography';
import Grid from '@material-ui/core/Grid';

export default function Details(props) {
    let { id, hash } = useParams();
    
    const [isOnline, setIsOnline] = useState(null);
    const {user, setUser } = useState([]);                
    let usr = [];
    const decryptedId = AESDecrypt(id);    
    var rec = users.map(item => {
        if(item.id === decryptedId) {
            console.log(item);                    
            usr=item;
        }
    });
    
    return (
        <div>
            <Grid container >
               <Grid xs={2}></Grid>

               <Grid xs={8}>
                    <Grid container >
                        <Grid xs={12} align="left">
                            <Typography variant="body1">
                                ID: {decryptedId}      
                            </Typography>
                        </Grid>                        
                        <Grid xs={12} align="left">
                            <Typography variant="body1">
                                Name: {usr.first} {usr.last}
                            </Typography>
                        </Grid>                        
                        <Grid xs={12} align="left">
                            <Typography variant="body1">
                                Hash Parameter: {hash}
                            </Typography>
                        </Grid>                        
                        <Grid xs={12} align="left">
                            <Typography variant="body1">
                                Hash Sha256Hash(): {Sha256Hash(usr.id, usr.first, usr.last)}
                            </Typography>
                        </Grid>                        
                        <Grid xs={12} align="left">
                            <Typography variant="body1">
                                {Sha256Hash(usr.id, usr.first, usr.last) === hash? 'Matching Hash' : 'No Match'}
                            </Typography>
                        </Grid>                        
                    </Grid>
               </Grid>

            </Grid>
                
        </div>
    )
}