npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@lindorm/enigma

v0.2.17

Published

Secure password hashing using Argon2 with optional multi-layer cryptographic protection.

Downloads

362

Readme

@lindorm/enigma

Secure password hashing using Argon2 with optional multi-layer cryptographic protection.

Installation

npm install @lindorm/enigma

Features

  • Argon2id Password Hashing: Industry-standard password hashing algorithm
  • Multi-Layer Security: Optional three-layer cryptographic protection
  • Configurable Security Parameters: Fine-tune memory, time, and parallelism
  • Secret Key Support: Add pepper for additional security
  • Type-Safe: Full TypeScript support
  • OWASP Compliant: Follows password storage best practices

Quick Start

Basic Password Hashing with ArgonKit

import { ArgonKit } from "@lindorm/enigma";

const argon = new ArgonKit();

// Hash a password
const hash = await argon.hash("user-password");

// Verify a password
const isValid = await argon.verify("user-password", hash);

// Assert password (throws if invalid)
await argon.assert("user-password", hash);

Enhanced Security with Enigma

import { Enigma } from "@lindorm/enigma";
import { KryptosAes, KryptosOct } from "@lindorm/kryptos";

// Create encryption keys
const aesKey = KryptosAes.generate({ algorithm: "A256GCM" });
const octKey = KryptosOct.generate({ algorithm: "HS512" });

const enigma = new Enigma({
  aes: { kryptos: aesKey },
  oct: { kryptos: octKey }
});

// Hash with three layers of security
const secureHash = await enigma.hash("sensitive-password");

// Verify through all layers
const isValid = await enigma.verify("sensitive-password", secureHash);

API Reference

ArgonKit Class

Direct Argon2 password hashing with configurable parameters.

Constructor Options

interface ArgonKitOptions {
  hashLength?: number;     // Output length in bytes (default: 256)
  memoryCost?: number;     // Memory in KiB (default: 65536 / 64MB)
  parallelism?: number;    // Parallel threads (default: 8)
  timeCost?: number;       // Iterations (default: 12)
  kryptos?: IKryptosOct;   // Optional secret key for pepper
}

Methods

hash(data: string): Promise<string>

Hashes the input data using Argon2id.

const hash = await argon.hash("password123");
// $argon2id$v=19$m=65536,t=12,p=8$...
verify(data: string, hash: string): Promise<boolean>

Verifies if the data matches the hash.

const isValid = await argon.verify("password123", hash);
console.log(isValid); // true or false
assert(data: string, hash: string): Promise<void>

Verifies and throws an error if invalid.

try {
  await argon.assert("password123", hash);
  // Password is correct
} catch (error) {
  // Password is incorrect
}

Enigma Class

Multi-layer cryptographic protection combining HMAC signing, Argon2 hashing, and AES encryption.

Constructor Options

interface EnigmaOptions {
  aes: {
    kryptos: IKryptosAes;    // AES key for encryption layer
  };
  oct: {
    kryptos: IKryptosOct;    // HMAC key for signing layer
  };
  argon?: ArgonKitOptions;   // Optional Argon2 configuration
}

Security Layers

  1. OCT/HMAC Signing: Signs the input data
  2. Argon2 Hashing: Hashes the signed data
  3. AES Encryption: Encrypts the hash

Methods

Same as ArgonKit: hash(), verify(), and assert().

Configuration Guide

Security Parameters

Memory Cost

Controls memory usage. Higher values increase security but require more RAM.

const argon = new ArgonKit({
  memoryCost: 131072  // 128MB (high security)
});

Recommendations:

  • Minimum: 47104 (46MB)
  • Default: 65536 (64MB)
  • High Security: 131072 (128MB)

Time Cost

Number of iterations. Higher values increase computation time.

const argon = new ArgonKit({
  timeCost: 20  // More iterations
});

Recommendations:

  • Minimum: 2
  • Default: 12
  • High Security: 20+

Parallelism

Number of parallel threads. Should match available CPU cores.

const argon = new ArgonKit({
  parallelism: 4  // 4 threads
});

Adding Pepper (Secret Key)

import { KryptosOct } from "@lindorm/kryptos";

// Generate or load a secret key
const pepper = KryptosOct.generate({ algorithm: "HS256" });

const argon = new ArgonKit({
  kryptos: pepper,
  memoryCost: 65536,
  timeCost: 12
});

// The pepper is automatically mixed into the hash
const hash = await argon.hash("password");

Security Best Practices

1. Choose Appropriate Parameters

// Standard security (default)
const standard = new ArgonKit();

// High security for sensitive data
const highSecurity = new ArgonKit({
  memoryCost: 131072,  // 128MB
  timeCost: 20,        // More iterations
  hashLength: 512      // Longer hash
});

// Performance-optimized
const performance = new ArgonKit({
  memoryCost: 47104,   // 46MB
  timeCost: 2,         // Minimum iterations
  parallelism: 4       // Fewer threads
});

2. Use Enigma for Critical Applications

// For highly sensitive data (medical records, financial data)
const enigma = new Enigma({
  aes: { kryptos: aesKey },
  oct: { kryptos: hmacKey },
  argon: {
    memoryCost: 131072,
    timeCost: 20
  }
});

3. Secure Key Management

// Store keys securely (environment variables, key management service)
const aesKey = KryptosAes.fromB64({
  privateKey: process.env.AES_PRIVATE_KEY,
  algorithm: "A256GCM"
});

const octKey = KryptosOct.fromB64({
  privateKey: process.env.HMAC_PRIVATE_KEY,
  algorithm: "HS512"
});

Examples

User Authentication Service

import { ArgonKit, ArgonError } from "@lindorm/enigma";

class AuthService {
  private argon: ArgonKit;

  constructor() {
    this.argon = new ArgonKit({
      memoryCost: 65536,
      timeCost: 12,
      parallelism: 8
    });
  }

  async registerUser(username: string, password: string): Promise<void> {
    const hash = await this.argon.hash(password);
    await saveToDatabase({ username, passwordHash: hash });
  }

  async loginUser(username: string, password: string): Promise<boolean> {
    const user = await getUserFromDatabase(username);
    if (!user) return false;

    try {
      await this.argon.assert(password, user.passwordHash);
      return true;
    } catch (error) {
      if (error instanceof ArgonError) {
        // Invalid password
        return false;
      }
      throw error;
    }
  }

  async changePassword(username: string, oldPassword: string, newPassword: string): Promise<void> {
    const user = await getUserFromDatabase(username);
    
    // Verify old password
    const isValid = await this.argon.verify(oldPassword, user.passwordHash);
    if (!isValid) {
      throw new Error("Invalid current password");
    }

    // Hash new password
    const newHash = await this.argon.hash(newPassword);
    await updateUserPassword(username, newHash);
  }
}

Secure Document Storage

import { Enigma } from "@lindorm/enigma";

class SecureDocumentService {
  private enigma: Enigma;

  constructor(aesKey: IKryptosAes, octKey: IKryptosOct) {
    this.enigma = new Enigma({
      aes: { kryptos: aesKey },
      oct: { kryptos: octKey },
      argon: {
        memoryCost: 131072,  // High security
        timeCost: 20
      }
    });
  }

  async storeDocument(documentId: string, accessCode: string): Promise<void> {
    // Create secure hash of access code
    const hash = await this.enigma.hash(accessCode);
    
    await saveDocument({
      id: documentId,
      accessHash: hash,
      createdAt: new Date()
    });
  }

  async verifyAccess(documentId: string, accessCode: string): Promise<boolean> {
    const document = await getDocument(documentId);
    
    return this.enigma.verify(accessCode, document.accessHash);
  }
}

Password Strength Requirements

interface PasswordPolicy {
  minLength: number;
  requireUppercase: boolean;
  requireLowercase: boolean;
  requireNumbers: boolean;
  requireSpecialChars: boolean;
}

class PasswordService {
  private argon: ArgonKit;
  private policy: PasswordPolicy;

  constructor(policy: PasswordPolicy) {
    this.argon = new ArgonKit();
    this.policy = policy;
  }

  validatePassword(password: string): string[] {
    const errors: string[] = [];

    if (password.length < this.policy.minLength) {
      errors.push(`Password must be at least ${this.policy.minLength} characters`);
    }

    if (this.policy.requireUppercase && !/[A-Z]/.test(password)) {
      errors.push("Password must contain uppercase letters");
    }

    if (this.policy.requireLowercase && !/[a-z]/.test(password)) {
      errors.push("Password must contain lowercase letters");
    }

    if (this.policy.requireNumbers && !/\d/.test(password)) {
      errors.push("Password must contain numbers");
    }

    if (this.policy.requireSpecialChars && !/[!@#$%^&*]/.test(password)) {
      errors.push("Password must contain special characters");
    }

    return errors;
  }

  async hashPassword(password: string): Promise<string> {
    const errors = this.validatePassword(password);
    if (errors.length > 0) {
      throw new Error(errors.join(", "));
    }

    return this.argon.hash(password);
  }
}

Performance Considerations

Benchmarking Your Configuration

async function benchmark() {
  const configs = [
    { name: "Low", memoryCost: 47104, timeCost: 2 },
    { name: "Default", memoryCost: 65536, timeCost: 12 },
    { name: "High", memoryCost: 131072, timeCost: 20 }
  ];

  for (const config of configs) {
    const argon = new ArgonKit(config);
    
    const start = Date.now();
    await argon.hash("benchmark-password");
    const duration = Date.now() - start;
    
    console.log(`${config.name}: ${duration}ms`);
  }
}

Async Operations

All operations are asynchronous to prevent blocking:

// Process multiple passwords concurrently
const passwords = ["pass1", "pass2", "pass3"];
const hashes = await Promise.all(
  passwords.map(p => argon.hash(p))
);

Error Handling

ArgonError

Thrown by ArgonKit for hashing/verification failures:

import { ArgonError } from "@lindorm/enigma";

try {
  await argon.assert("wrong-password", hash);
} catch (error) {
  if (error instanceof ArgonError) {
    console.log("Invalid password");
  }
}

EnigmaError

Thrown by Enigma for multi-layer verification failures:

import { EnigmaError } from "@lindorm/enigma";

try {
  await enigma.assert("wrong-password", hash);
} catch (error) {
  if (error instanceof EnigmaError) {
    console.log("Verification failed");
  }
}

Migration Guide

From bcrypt

// Before (bcrypt)
const bcrypt = require('bcrypt');
const hash = await bcrypt.hash(password, 10);
const isValid = await bcrypt.compare(password, hash);

// After (enigma)
import { ArgonKit } from "@lindorm/enigma";
const argon = new ArgonKit();
const hash = await argon.hash(password);
const isValid = await argon.verify(password, hash);

Upgrading Hash Security

async function upgradePasswordHash(username: string, password: string, oldHash: string) {
  // Verify with old system
  const isValid = await oldSystem.verify(password, oldHash);
  if (!isValid) return false;

  // Create new Argon2 hash
  const argon = new ArgonKit();
  const newHash = await argon.hash(password);
  
  // Update database
  await updateUserHash(username, newHash);
  return true;
}

Security Notes

  • Argon2id is resistant to both side-channel and GPU attacks
  • Default parameters follow OWASP recommendations
  • Always use HTTPS when transmitting passwords
  • Never log or store plaintext passwords
  • Consider rate limiting authentication attempts
  • Use Enigma for compliance requirements (HIPAA, PCI-DSS)

License

AGPL-3.0-or-later