Introduction

RSA algorithm is an asymmetric cryptography algorithm. Asymmetric actually means that it works on two different keys, i.e., public key and private key. As the name describes, the public key is given to everyone, and the private key is kept private.

We are going to encrypt and decrypt data as "The encryptRSA method encrypts large data by breaking it into smaller chunks (86 bytes), encrypting each chunk individually with RSA, and then concatenating the Base64-encoded encrypted chunks into a final string. This approach is necessary because RSA can only encrypt a limited amount of data at a time due to its key size limitations. The final result is a single string that represents the encrypted data."

Step 1. Install the jsencrypt Library.

npm install jsencrypt

Step 2. Import Forge in the component or service that you would like to use.

import * as Forge from 'node-forge';

Step 3. Complete Encryption Method.

// RSA Encryption
encryptRSA(data: any): string {
  const publickey: string = ``; // Replace your own public key
  const rsa = Forge.pki.publicKeyFromPem(publickey);
  const jsonData = data;
  const chunkSize = 86; 
  let finalEncrypted = '';   

  for (let i = 0; i < jsonData.length; i += chunkSize) {
    const chunk = jsonData.substring(i, i + chunkSize);
    const encryptedChunk = rsa.encrypt(chunk);
    finalEncrypted += Forge.util.encode64(encryptedChunk);
  } 
  return finalEncrypted;
}

Breakdown of the encryption method

Step 1. Forge.pki.publicKeyFromPem: Converts the PEM-encoded public key into a format that the node-forge library can use for encryption.

const rsa = Forge.pki.publicKeyFromPem(this.publickey);

Step 2

for (let i = 0; i < jsonData.length; i += chunkSize) {
  const chunk = jsonData.substring(i, i + chunkSize);
  const encryptedChunk = rsa.encrypt(chunk);
  finalEncrypted += Forge.util.encode64(encryptedChunk);
}

Output Sample for Encryption

Encryption

Decryption Complete Method

// RSA Decryption
decryptionRSA(value: any): any {
  var privatekey: string = ``; // replace your private key

  const rsa = Forge.pki.privateKeyFromPem(this.privatekey);
  var ctBytes = Forge.util.decode64(value);    
  var plaintextBytes = rsa.decrypt(ctBytes);
  
  return plaintextBytes.toString();
}

Output Sample for Decryption

Decryption

Complete encryption and decryption Service

import { Injectable } from '@angular/core';
import * as CryptoJS from 'crypto-js';
import * as Forge from 'node-forge';

@Injectable({
  providedIn: 'root'
})
export class EncryptionService {

  private secretKey: string = ''; // Replace with a secure key
  private Vector: string = '';
  private publickey: string = ``;  
  private privatekey: string = ``;

  constructor() {}

  // AES encryption
  encrypt(value: string): string {
    return CryptoJS.AES.encrypt(value, this.secretKey, {
      iv: CryptoJS.enc.Utf8.parse(this.Vector),
      mode: CryptoJS.mode.CBC,
      padding: CryptoJS.pad.Pkcs7,  
    }).toString();
  }
  
  encryptObject(value: any): string {
    return CryptoJS.AES.encrypt(JSON.stringify(value), this.secretKey, {
      iv: CryptoJS.enc.Utf8.parse(this.Vector),
      mode: CryptoJS.mode.CBC,
      padding: CryptoJS.pad.Pkcs7,  
    }).toString();
  }

  // AES Decryption
  decrypt(encryptedText: string): string {
    const decrypted = CryptoJS.AES.decrypt(encryptedText, this.secretKey, {
      iv: CryptoJS.enc.Utf8.parse(this.Vector),
      mode: CryptoJS.mode.CBC,
      padding: CryptoJS.pad.Pkcs7,
    });
    return decrypted.toString(CryptoJS.enc.Utf8);
  }

  // Encryption using CBC Triple DES
  encryptUsingTripleDES(res: any, typeObj: boolean): string {
    const data = typeObj ? JSON.stringify(res) : res;
    const keyHex = CryptoJS.enc.Utf8.parse(this.secretKey);
    const iv = CryptoJS.enc.Utf8.parse(this.Vector);
    const mode = CryptoJS.mode.CBC;
    const encrypted = CryptoJS.TripleDES.encrypt(data, keyHex, { iv, mode });
    return encrypted.toString();
  }

  // Decryption using CBC Triple DES
  decryptUsingTripleDES(encrypted: string): string {
    const keyHex = CryptoJS.enc.Utf8.parse(this.secretKey);
    const iv = CryptoJS.enc.Utf8.parse(this.Vector);
    const mode = CryptoJS.mode.CBC;
    const decrypted = CryptoJS.TripleDES.decrypt(encrypted, keyHex, { iv, mode });
    return decrypted.toString(CryptoJS.enc.Utf8);
  }

  // RSA Encryption
  encryptRSA(data: any): string {
    const rsa = Forge.pki.publicKeyFromPem(this.publickey);
    const jsonData = data;
    const chunkSize = 86; 
    let finalEncrypted = '';   
    
    for (let i = 0; i < jsonData.length; i += chunkSize) {
      const chunk = jsonData.substring(i, i + chunkSize);
      const encryptedChunk = rsa.encrypt(chunk);
      finalEncrypted += Forge.util.encode64(encryptedChunk);
    } 
    return finalEncrypted;
  }

  encryptObjectRSA(data: any): string {
    const rsa = Forge.pki.publicKeyFromPem(this.publickey);
    const jsonData = JSON.stringify(data);
    const chunkSize = 86; 
    let finalEncrypted = '';   
    
    for (let i = 0; i < jsonData.length; i += chunkSize) {
      const chunk = jsonData.substring(i, i + chunkSize);
      const encryptedChunk = rsa.encrypt(chunk);
      finalEncrypted += Forge.util.encode64(encryptedChunk);
    } 
    return finalEncrypted;
  }

  // RSA Decryption 
  decryptionRSA(value: any): any {
    const rsa = Forge.pki.privateKeyFromPem(this.privatekey);
    const ctBytes = Forge.util.decode64(value);    
    const plaintextBytes = rsa.decrypt(ctBytes);
    return plaintextBytes.toString();
  } 
}

When working with RSA encryption, several options and configurations can affect how encryption is performed. Below are the different options you can consider.

1. Key Size

2. Padding Schemes

3. Block Size and Chunking

4. RSA Modes

5. Asymmetric vs. Symmetric Encryption in Hybrid Models

6. Implementation Libraries

7. Encoding Formats

8. Error Handling and Security Considerations

Summary

The options for RSA encryption revolve around key size, padding schemes, data chunking, and the specific implementation library you choose. For the strongest security, using a 2048-bit or larger key with OAEP padding is recommended. For larger data, consider using hybrid encryption where RSA encrypts a symmetric key, and the symmetric key encrypts the data. Additionally, selecting the appropriate encoding format and properly managing keys is critical for secure RSA encryption.