Logo

dev-resources.site

for different kinds of informations.

Comprehensive Encryption and Security Service in NestJS: Argon2 Hashing, Token Generation, and AES Encryption

Published at
11/11/2024
Categories
nestjs
argon2
aes
encryption
Author
imzihad21
Categories
4 categories in total
nestjs
open
argon2
open
aes
open
encryption
open
Author
9 person written this
imzihad21
open
Comprehensive Encryption and Security Service in NestJS: Argon2 Hashing, Token Generation, and AES Encryption

Security is a top priority when building backend services, especially in applications dealing with sensitive data. In this guide, we'll build an EncryptionService in NestJS that covers a broad range of security features, including:

  • Password hashing and verification using Argon2, known for its high security and resistance to attacks.
  • Unique token generation for actions that require unique identifiers or session handling.
  • AES encryption and decryption for secure data storage or transmission.

This multi-featured approach provides a robust solution to common security needs in a backend service.

Setting Up the EncryptionService

First, we’ll configure the service with environment-based encryption parameters. By utilizing NestJS's ConfigService, we can manage sensitive information, such as encryption keys, more securely.

import {
  BadRequestException,
  Injectable,
  InternalServerErrorException,
  Logger,
} from "@nestjs/common";
import { ConfigService } from "@nestjs/config";
import * as argon2 from "argon2";
import { createCipheriv, createDecipheriv, createHash } from "crypto";
import * as uuid from "uuid";
import * as base64url from "base64url";

@Injectable()
export class EncryptionService {
  private readonly logger = new Logger(EncryptionService.name);
  private readonly algorithm = "aes-256-cbc";
  private readonly ivLength = 16;
  private readonly secretKey: string;

  constructor(private configService: ConfigService) {
    this.secretKey = this.configService.get<string>("ENCRYPTION_SECRET", "default_secret");
  }
Enter fullscreen mode Exit fullscreen mode

In this configuration:

  • Algorithm and IV Length: Set to aes-256-cbc and an IV length of 16 bytes, respectively, for strong encryption.
  • Secret Key: Loaded from environment variables, offering flexibility and enhancing security.

Secure Password Hashing with Argon2

Argon2 is a memory-hard algorithm designed to be secure against brute-force attacks, making it ideal for password storage. We’ll implement methods to hash passwords and verify hashed passwords with raw inputs.

  async hashPassword(rawPassword: string): Promise<string> {
    if (!rawPassword) {
      this.logger.error("Password is required");
      throw new BadRequestException("Password is required");
    }

    try {
      return await argon2.hash(rawPassword);
    } catch (err) {
      this.logger.error("Failed to hash password", err);
      throw new InternalServerErrorException("Failed to hash password");
    }
  }

  async verifyPassword(rawPassword: string = "", hashedPassword: string = ""): Promise<boolean> {
    if (!rawPassword) {
      this.logger.error("Password is required");
      throw new BadRequestException("Password is required");
    }

    try {
      return await argon2.verify(hashedPassword, rawPassword);
    } catch (err) {
      this.logger.error("Failed to verify password", err);
      throw new InternalServerErrorException("Failed to verify password");
    }
  }
Enter fullscreen mode Exit fullscreen mode
  • hashPassword: Creates a secure hash from a raw password using Argon2, with error handling for unexpected issues.
  • verifyPassword: Compares a raw password to a hashed password, ensuring only authorized access is allowed.

Temporary Password Generation

The generateTemporaryPassword function in the EncryptionService provides a way to create secure, random passwords. This is particularly useful in scenarios where users need a temporary password or a randomly generated password as part of the account recovery process or for initial account setup.

Here's a breakdown of how this function works:

  generateTemporaryPassword(length = 10) {
    const lowercaseChars = "abcdefghijklmnopqrstuvwxyz";
    const uppercaseChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    const numericChars = "0123456789";
    const specialChars = "!@#$%^&*()-_+=";

    const allChars = lowercaseChars + uppercaseChars + numericChars + specialChars;
    let password = "";

    try {
      for (let i = 0; i < length; i++) {
        const randomIndex = Math.floor(Math.random() * allChars.length);
        password += allChars[randomIndex];
      }
    } catch (error) {
      throw new InternalServerErrorException("Failed to generate a password");
    }

    return password;
  }
Enter fullscreen mode Exit fullscreen mode

This method is flexible and allows you to specify different password lengths by passing a length parameter, defaulting to 10 characters if no length is provided.

Unique Token Generation

In cases where a unique identifier is needed, such as session IDs or verification tokens, generating a unique, hard-to-guess string is critical. Here, we use UUID and base64 encoding for this purpose.

  generateUniqueToken(length: number = 3): string {
    const mergedUuid = Array.from({ length }, () => uuid.v4()).join("");
    const tokenBuffer = Buffer.from(mergedUuid.replace(/-/g, ""), "hex");
    return base64url.default(tokenBuffer);
  }
Enter fullscreen mode Exit fullscreen mode

This method generates a unique token using multiple UUIDs for greater uniqueness, making it suitable for scenarios requiring temporary identifiers.

AES Encryption and Decryption for Sensitive Data

AES encryption is widely used for securing sensitive data. Below, we create methods for encrypting and decrypting strings using AES-256 with a CBC mode.

Encrypting Data

  encryptString(text: string): string {
    if (!text) throw new Error("Text is required for encryption");

    try {
      const key = createHash("sha256").update(this.secretKey).digest("base64").slice(0, 32);
      const iv = Buffer.alloc(this.ivLength, 0);

      const cipher = createCipheriv(this.algorithm, key, iv);
      let encrypted = cipher.update(text, "utf8", "base64");
      encrypted += cipher.final("base64");

      return encrypted.replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
    } catch (error) {
      this.logger.error("Encryption failed", error);
      throw new InternalServerErrorException("Encryption failed");
    }
  }
Enter fullscreen mode Exit fullscreen mode

Decrypting Data

  decryptString(cipherText: string): string {
    if (!cipherText) throw new Error("Cipher text is required for decryption");

    try {
      const base64Text = cipherText.replace(/-/g, "+").replace(/_/g, "/");
      const key = createHash("sha256").update(this.secretKey).digest("base64").slice(0, 32);
      const iv = Buffer.alloc(this.ivLength, 0);

      const decipher = createDecipheriv(this.algorithm, key, iv);
      let decrypted = decipher.update(base64Text, "base64", "utf8");
      decrypted += decipher.final("utf8");

      return decrypted;
    } catch (error) {
      this.logger.error("Decryption failed", error);
      throw new InternalServerErrorException("Decryption failed");
    }
  }
Enter fullscreen mode Exit fullscreen mode

The encryption and decryption methods use a secure key derived from the secret key. The encrypted data is base64-encoded for safer storage and transmission.

Setting Up the EncryptionModule

To make EncryptionService available across the application, we encapsulate it within a globally accessible module: EncryptionModule.

import { Global, Module } from "@nestjs/common";
import { EncryptionService } from "./encryption.service";

@Global()
@Module({
  providers: [EncryptionService],
  exports: [EncryptionService],
})
export class EncryptionModule {}
Enter fullscreen mode Exit fullscreen mode

Conclusion

This EncryptionService implementation provides a highly secure way to handle encryption, hashing, and token generation in a NestJS application. It uses best-in-class algorithms such as Argon2 for hashing and AES-256 for encryption, making it versatile and secure for any backend project.

With this setup, you’ll have a robust foundation for safeguarding sensitive information, enabling more secure application development.

encryption Article's
30 articles in total
Favicon
Encryption in React Native apps enhances data security, protecting user information and ensuring privacy. However, it also presents challenges, such as performance overhead and complex implementation
Favicon
A Deep Dive into WhatsApp’s Encryption: Identity, Keys, and Message Security
Favicon
The Birthday Paradox: A Statistical Breakdown and How it Relates to Online Security
Favicon
Obfuscating “Hello world!” obfuscate on Python
Favicon
Introducing Inline Cryptography Toolkit: Simplify Encryption, Decryption, and Hashing in VS Code 🚀
Favicon
Advantages of Asymmetric Encryption with Random Public and Symmetric Private Keys
Favicon
Cloud Security Challenges and Encryption, Identity Management, and Compliance
Favicon
Microsoft Certified Azure Administrator Associate Exam (AZ-104) Lab Preparation #5: Azure Disk Encryption
Favicon
Encryption: ciphers, digests, salt, IV
Favicon
The Evolution of Hashing Algorithms: From MD5 to Modern Day
Favicon
Email Security and Data Protection for Startups: Affordable Solutions
Favicon
Understanding SNI (Server Name Indication) and Modern Encryption Solutions
Favicon
What is RSA Asymmetric Encryption? Basics, Principles and Applications
Favicon
Encryption Vs. Decryption: What’s the Difference?
Favicon
Laravel Data Encryption and Decryption
Favicon
Unveiling A Groundbreaking Open-Source Encrypted Machine Learning Framework
Favicon
Secure Text Encryption and Decryption with Vanilla JavaScript
Favicon
Understanding SSL/TLS: The Role of Encryption and Security Protocols in Internet Communication
Favicon
Implications for Encryption and Cybersecurity with Quantum Computing
Favicon
How to Generate Your Own Public and Secret Keys for PGP Encryption
Favicon
Does S/MIME Encrypt Emails and Attachments?
Favicon
What is Token Signing in Software Publisher Certificate?
Favicon
Encryption Symmetric
Favicon
Secret management for the layman
Favicon
JavaScript Base-32 Encryption
Favicon
Comprehensive Encryption and Security Service in NestJS: Argon2 Hashing, Token Generation, and AES Encryption
Favicon
Difference Between Encryption and Hashing 🔐🔑
Favicon
Ransomware Explained: How It Works and Best Defense Mechanisms to Protect Your Data
Favicon
Debunking Most Common Cloud Computing Myths & Misconceptions
Favicon
Implementing HTTP Request and Response Encryption in ASP.NET Core with Custom Attributes

Featured ones: