This technical guide presents a production-ready security service implementation for NestJS applications, integrating essential cryptographic operations while adhering to industry-standard security protocols. The EncryptionService encapsulates critical functionality for modern backend systems, featuring Argon2 password hashing, AES-256 data encryption, and secure token generation within a modular architecture.
Core Service Configuration
The foundation establishes environment-aware cryptographic parameters using NestJS configuration patterns:
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");
  }
Security Architecture
- Algorithm Selection: AES-256-CBC provides FIPS-approved symmetric encryption
- IV Management: Fixed-length initialization vector for CBC mode compatibility
- Secret Handling: Environment variable injection prevents key hardcoding
- Fallback Mechanism: Default secret enables development environments while enforcing production configuration
Password Security Implementation
1. Argon2 Password Hashing
Implements memory-hard hashing for credential protection:
  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");
    }
  }
Enterprise Security Features
- Timing Attack Resistance: Constant-time verification implementation
- Memory Hardness: Configurable memory/iteration parameters (implicit in argon2.hash)
- Validation Enforcement: Strict input checking prevents empty credential processing
2. Temporary Password Generation
Implements complex password synthesis for recovery workflows:
  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;
  }
Security Considerations
- Character Diversity: Four distinct character classes minimize pattern predictability
- Length Configuration: Adjustable complexity through parameterization
- Entropy Management: Combined character pools enhance combinatorial complexity
Cryptographic Token Management
UUID-Based Token Generation
Creates collision-resistant identifiers for session management:
  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);
  }
Cryptographic Properties
- UUID v4 Utilization: 122-bit random number space guarantees uniqueness
- Base64URL Encoding: URL-safe representation for web compatibility
- Concatenation Strategy: Multiple UUIDs enhance token entropy
Symmetric Data Encryption
1. AES-256-CBC Encryption
Implements FIPS 197-compliant data protection:
  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");
    }
  }
2. AES-256-CBC Decryption
Ensures reliable data recovery process:
  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");
    }
  }
Cryptographic Implementation Details
- Key Derivation: SHA-256 hashing ensures fixed-length key material
- IV Strategy: Zero-byte initialization vector (production implementations should use random IVs)
- Encoding Handling: Base64URL conversion for web-safe ciphertext representation
Service Modularization
Global module declaration enables cross-application accessibility:
import { Global, Module } from "@nestjs/common";
import { EncryptionService } from "./encryption.service";
@Global()
@Module({
  providers: [EncryptionService],
  exports: [EncryptionService],
})
export class EncryptionModule {}
Architectural Benefits
- Singleton Pattern: Single service instance across application modules
- Dependency Management: Centralized cryptographic functionality
- Security Consistency: Uniform implementation across application layers
Production Deployment Considerations
- 
Secret Management - Implement rotational policies for encryption secrets
- Integrate with vault services for secure key storage
 
- 
Performance Optimization - Benchmark Argon2 parameters against server capabilities
- Consider hardware acceleration for cryptographic operations
 
- 
Compliance Requirements - Align with PCI-DSS for payment data handling
- Implement FIPS 140-2 validation where required
 
- 
Attack Mitigation - Rate-limiting for password verification attempts
- Automated secret rotation mechanisms
 
This implementation provides a robust security foundation for NestJS applications, addressing critical requirements for:
- Credential Protection: Memory-hard hashing prevents brute-force attacks
- Data Confidentiality: Strong encryption safeguards sensitive information
- Session Security: Unpredictable tokens mitigate session hijacking risks
- Operational Reliability: Comprehensive error handling ensures system stability
The modular design facilitates seamless integration with enterprise security ecosystems, providing a critical layer in defense-in-depth strategies while maintaining developer productivity through standardized cryptographic primitives.
 

 
    
Top comments (0)