Cryptography
A comprehensive TypeScript cryptography library providing secure encryption, digital signatures, JWT token management, and Web3-compatible cryptographic operations.
Features
- AES-256-GCM Encryption: Secure two-way encryption and decryption
- Digital Signatures: RSA and ECC-based signature generation and verification
- JWT Token Management: Token creation, validation, and verification
- API Key Management: Secure API key generation and verification with HMAC
- OTP (One-Time Password): TOTP-based authentication with configurable parameters
- Web3 Compatibility: Blockchain address generation and signature schemes
- Key Management: Secure key generation and environment-based configuration
- Hash Functions: SHA-256, SHA-512, and HMAC operations
- Slug Generation: Human-readable unique identifiers with multiple dictionaries
- Encoding Utilities: Base64 encoding/decoding and validation
Installation
yarn install
Environment Setup
Quick Start
Generate secure cryptographic keys:
# Generate new .env file with secure keys
node generate.js generate
# Or show keys without saving
node generate.js show
Manual Setup
Create a .env
file with the following variables:
CRYPTO_AES_ENCRYPTION_KEY=<64-character-hex-string>
CRYPTO_HMAC_SIGNING_KEY=<64-character-hex-string>
Key Requirements
- Both keys must be exactly 64 hexadecimal characters (32 bytes)
- Keys must contain only valid hex characters (0-9, a-f, A-F)
- Use cryptographically secure random generation
Internal Entropy Generation
The library now features built-in entropy generation that eliminates the need for external key pool files:
- Self-contained: No external
pool.json
file required - Cryptographically secure: Uses Node.js
crypto.randomBytes()
for all entropy generation - Dynamic generation: Fresh entropy generated on-demand for each operation
- Backward compatible: Existing code works unchanged
Usage
Basic Usage (Environment Variables)
import { Cryptography } from './index'
const crypto = new Cryptography()
const encrypted = crypto.encrypt('Hello, World!')
const decrypted = crypto.decrypt(encrypted)
const signature = crypto.signature()
const isValid = crypto.signatureVerify(signature)
const token = crypto.jwtIssue({ userId: 123 }, '1h')
const payload = crypto.jwtVerify(token)
const apiKey = crypto.apiKey()
const isValidKey = crypto.apiKeyVerify(apiKey)
// OTP (One-Time Password) functionality
const otpEnrollment = crypto.otpEnrol({ identifier: 'user@example.com', issuer: 'MyApp' })
const otpCode = crypto.otpIssue({ secret: otpEnrollment.secret })
const isValidOTP = crypto.otpVerify({ secret: otpEnrollment.secret, token: otpCode })
const slug = crypto.slug()
const customSlug = crypto.slug({ separator: '_', length: 5 })
Custom Configuration
const crypto = new Cryptography({
encryptKey: 'your64hexencryptionkey...',
encryptKeySingle: 'your64hexsigningkey...',
})
Mixed Configuration
const crypto = new Cryptography({
encryptKey: 'explicit64hexkey...',
// encryptKeySingle will use CRYPTO_HMAC_SIGNING_KEY from environment
})
🎮 Interactive Demo
Experience all cryptography features through our beautiful web interface:
# Start the demo server
npm run demo
# Open in browser: http://localhost:8080
Demo Features
- 🎲 Key Generation: Random strings, predefined strengths, salts, crypto addresses
- 🔒 Encryption: AES-256-GCM, one-way encryption, password hashing
- ✍️ Digital Signatures: Generation, verification, key pairs
- 🎫 JWT Tokens: Issue and verify tokens with custom payloads
- 🔑 API Keys: Secure API key generation and verification with custom prefixes
- 🏷️ Slug Generation: Human-readable unique identifiers with multiple dictionaries
- 🔧 Utilities: Base64 encoding, environment key generation
The demo interface provides an interactive way to test all cryptographic operations with a modern, responsive design inspired by professional crypto tools.
API Reference
Constructor
The Cryptography class now features internal entropy generation for enhanced security and self-containment.
import { Cryptography } from './index'
// Basic initialization with environment variables
const crypto = new Cryptography()
// Custom configuration with explicit keys
const crypto = new Cryptography({
encryptKey: 'your64hexencryptionkey...',
encryptKeySingle: 'your64hexsigningkey...',
})
// Mixed configuration (some explicit, some from environment)
const crypto = new Cryptography({
encryptKey: 'explicit64hexkey...',
// encryptKeySingle will use CRYPTO_HMAC_SIGNING_KEY from environment
})
Constructor Options:
encryptKey?: string
- AES-256 encryption key (64 hex chars) or usesCRYPTO_AES_ENCRYPTION_KEY
env varencryptKeySingle?: string
- HMAC signing key (64 hex chars) or usesCRYPTO_HMAC_SIGNING_KEY
env var
Internal Entropy Features:
- Automatic entropy generation: No external files required
- Cryptographically secure: Uses Node.js
crypto.randomBytes()
- Dynamic key generation: Fresh entropy for each operation
- Backward compatible: Existing code works unchanged
Random String Generation
random(options: RandomOptions): string
Generate cryptographically secure random strings with customizable character sets.
Options:
length?: number
- String length (default: 32)useLowerCase?: boolean
- Include lowercase letters (default: true)useUpperCase?: boolean
- Include uppercase letters (default: true)useNumbers?: boolean
- Include numbers (default: true)useSpecial?: boolean
- Include special characters (default: false)useHex?: boolean
- Include hex characters (default: false)
const random = crypto.random({})
console.log(random) // 'a1B2c3D4e5F6g7H8i9J0k1L2m3N4o5P6'
const password = crypto.random({
length: 20,
useLowerCase: true,
useUpperCase: true,
useNumbers: true,
useSpecial: true,
})
console.log(password) // '*ajz:74,*ak0mN$9Hx2!'
const lowercase = crypto.random({
length: 15,
useLowerCase: true,
useUpperCase: false,
useNumbers: false,
useSpecial: false,
})
console.log(lowercase) // 'abcdefghijklmno'
const hexString = crypto.random({
length: 12,
useLowerCase: false,
useUpperCase: false,
useNumbers: false,
useSpecial: false,
useHex: true,
})
console.log(hexString) // 'A1B2C3D4E5F6'
const edgeCase = crypto.random({ length: 1 })
console.log(edgeCase.length) // 1
const largeRandom = crypto.random({ length: 1000 })
console.log(largeRandom.length) // 1000
const uniqueResults = []
for (let i = 0; i < 100; i++) {
uniqueResults.push(crypto.random({ length: 20 }))
}
console.log(new Set(uniqueResults).size) // 100 (all unique)
get(strength: KeyStrength): string
Generate predefined strength keys for specific use cases.
Strength Options:
decent_pw
- 10 characters, alphanumericstrong_pw
- 15 characters, alphanumeric + specialft_knox_pw
- 30 characters, alphanumeric + specialci_key
- 32 characters, alphanumeric160_wpa
- 20 characters, alphanumeric + special504_wpa
- 63 characters, alphanumeric + special64_wep
- 5 characters, hex only128_wep
- 13 characters, hex only152_wep
- 16 characters, hex only256_wep
- 29 characters, hex only
crypto.get('decent_pw')
crypto.get('strong_pw') // 'i=SQ_qa3W[<RxoM'
crypto.get('ft_knox_pw') // 'P}U%H\OOYAYb;wc"3hgI,3Lz[gd-z]'
crypto.get('ci_key') // 'CeXHpM3nDgzdv0o3AkMCs3OuxzepLGW8'
crypto.get('160_wpa') // 'oHI#gR8z#h7BS>cZ!zH('
crypto.get('504_wpa') // '<os[g`s}u06jqt"Ea]t11,HsI[UipHD)%F";:9RhJ@kTU8GknLpMAXtoCzsJjT`'
crypto.get('64_wep') // '8911B'
crypto.get('128_wep') // '9F4E4F933BCCC'
crypto.get('152_wep') // '695E1EE96E483961'
crypto.get('256_wep') // 'AC7E866246BA6B71BF5D88A6861AB'
salt(): string
Generate cryptographic salt for password hashing.
const salt = crypto.salt()
console.log(salt) // '5eb63bbbe01eeed093cb22bb8f5acdc3'
console.log(salt.length) // 32 (16 bytes hex-encoded)
Encryption Methods
encrypt(data: string): string
Two-way AES-256-GCM encryption with authentication.
const plaintext = 'Hello, World!'
const encrypted = crypto.encrypt(plaintext)
const unicode = crypto.encrypt('🚀 Hello 世界 🌍')
const special = crypto.encrypt('!@#$%^&*()_+-=[]{}|;:,.<>?`~')
const number = crypto.encrypt(12345) // '12345'
const boolean = crypto.encrypt(true) // 'true'
const nullValue = crypto.encrypt(null) // 'null'
const undefinedValue = crypto.encrypt(undefined) // 'undefined'
const largeText = crypto.encrypt('a'.repeat(10000))
const jsonData = crypto.encrypt(
JSON.stringify({
message: 'Hello',
number: 42,
nested: { array: [1, 2, 3] },
})
)
const multilineText = crypto.encrypt(`Line 1
Line 2
Line 3`)
const empty = crypto.encrypt('')
const differentForSameInput1 = crypto.encrypt('test')
const differentForSameInput2 = crypto.encrypt('test')
console.log(differentForSameInput1 !== differentForSameInput2) // true
decrypt(encryptedData: string): string
Decrypt AES-256-GCM encrypted data with authentication verification.
const plaintext = 'Hello, World!'
const encrypted = crypto.encrypt(plaintext)
const decrypted = crypto.decrypt(encrypted)
console.log(decrypted) // 'Hello, World!'
const original = '🚀 Unicode test 中文'
const encrypted = crypto.encrypt(original)
const decrypted = crypto.decrypt(encrypted)
console.log(decrypted === original) // true
try {
crypto.decrypt('invalid:format:here')
} catch (error) {
console.log('Decryption failed - invalid format')
}
encryptSingle(data: string): string
One-way HMAC-based encryption (deterministic output).
const data = 'Hello, World!'
const hash1 = crypto.encryptSingle(data)
const hash2 = crypto.encryptSingle(data)
console.log(hash1 === hash2) // true
const hash3 = crypto.encryptSingle('Different data')
console.log(hash1 !== hash3) // true
console.log(hash1) // 'YWxnQmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ejEyMzQ1Ng=='
const numericHash = crypto.encryptSingle(12345)
const booleanHash = crypto.encryptSingle(true)
const nullHash = crypto.encryptSingle(null)
Digital Signatures
signature(): string
Generate encrypted digital signature using internal keys.
const signature = crypto.signature()
console.log(signature.split(':').length) // 3 components
signatureVerify(signature: string): boolean
Verify digital signature authenticity.
const signature = crypto.signature()
const isValid = crypto.signatureVerify(signature)
console.log(isValid) // true
try {
const invalidSig = crypto.encrypt('unknown1 unknown2')
crypto.signatureVerify(invalidSig)
} catch (error) {
console.log('Unknown identifier')
}
Cryptographic Address Generation
address(): string
Generate blockchain-compatible crypto addresses.
const address = crypto.address()
console.log(address.length) // 32 characters
console.log(address.startsWith('k')) // true
console.log(address.match(/^k[a-zA-Z0-9]+$/)) // Valid format
const addresses = Array.from({ length: 5 }, () => crypto.address())
console.log(new Set(addresses).size) // 5 (all unique)
Password Hashing
password(password: string, salt: string): string
Generate secure password hash using PBKDF2.
const password = 'mySecurePassword123'
const salt = crypto.salt()
const hash = crypto.password(password, salt)
console.log(hash.length) // 512 characters (256 bytes hex-encoded)
const hash1 = crypto.password('test', salt)
const hash2 = crypto.password('test', salt)
console.log(hash1 === hash2) // true
const salt1 = crypto.salt()
const salt2 = crypto.salt()
const hash3 = crypto.password('test', salt1)
const hash4 = crypto.password('test', salt2)
console.log(hash3 !== hash4) // true
const unicodeHash = crypto.password('🚀 Password 世界', salt)
const specialHash = crypto.password('!@#$%^&*()', salt)
Key Pair Generation
privateKey(): string
Generate elliptic curve private key (secp521r1).
const privateKey = crypto.privateKey()
console.log(privateKey.includes('-----BEGIN PRIVATE KEY-----')) // true
console.log(privateKey.includes('-----END PRIVATE KEY-----')) // true
console.log(privateKey.length > 200) // true
const key1 = crypto.privateKey()
const key2 = crypto.privateKey()
console.log(key1 !== key2) // true
publicKey(privateKey: string): string
Derive public key from private key.
const privateKey = crypto.privateKey()
const publicKey = crypto.publicKey(privateKey)
console.log(publicKey.includes('-----BEGIN PUBLIC KEY-----')) // true
console.log(publicKey.includes('-----END PUBLIC KEY-----')) // true
const publicKey1 = crypto.publicKey(privateKey)
const publicKey2 = crypto.publicKey(privateKey)
console.log(publicKey1 === publicKey2) // true
try {
crypto.publicKey('invalid-key')
} catch (error) {
console.log('Invalid private key format')
}
publicKeyVerify({ privateKey, publicKey }): boolean
Verify key pair authenticity using digital signatures.
const privateKey = crypto.privateKey()
const publicKey = crypto.publicKey(privateKey)
const isValid = crypto.publicKeyVerify({ privateKey, publicKey })
console.log(isValid) // true
const privateKey1 = crypto.privateKey()
const privateKey2 = crypto.privateKey()
const publicKey2 = crypto.publicKey(privateKey2)
try {
crypto.publicKeyVerify({
privateKey: privateKey1,
publicKey: publicKey2,
})
} catch (error) {
console.log('Failed to authenticate the public key')
}
JWT Token Management
jwtIssue(payload: object, expiresIn: string): string
Create signed JWT tokens with custom payloads.
const payload = {
userId: '12345',
username: 'testUser',
role: 'admin',
}
const token = crypto.jwtIssue(payload, '1h')
console.log(token.split('.').length) // 3 (header.payload.signature)
const token1h = crypto.jwtIssue(payload, '1h') // 1 hour
const token30m = crypto.jwtIssue(payload, '30m') // 30 minutes
const token7d = crypto.jwtIssue(payload, '7d') // 7 days
const complexPayload = {
userId: 'user_12345',
username: 'john.doe@example.com',
roles: ['admin', 'user', 'moderator'],
permissions: {
read: true,
write: true,
delete: false,
},
metadata: {
lastLogin: '2025-07-10T10:00:00Z',
loginCount: 42,
},
}
const complexToken = crypto.jwtIssue(complexPayload, '2h')
const minimalToken = crypto.jwtIssue({}, '1h')
const specialPayload = {
specialChars: '!@#$%^&*()_+-=[]{}|;\':",./<>?',
unicode: '🔐 Security test 안전',
}
const specialToken = crypto.jwtIssue(specialPayload, '1h')
jwtVerify(token: string): object
Verify and decode JWT tokens.
const payload = { userId: '12345', role: 'admin' }
const token = crypto.jwtIssue(payload, '1h')
const verified = crypto.jwtVerify(token)
console.log(verified.userId) // '12345'
console.log(verified.role) // 'admin'
console.log(verified.iat) // Issue time (timestamp)
console.log(verified.exp) // Expiry time (timestamp)
const complexPayload = {
array: [1, 2, 3],
nested: { level1: { level2: { level3: 'deep' } } },
}
const complexToken = crypto.jwtIssue(complexPayload, '1h')
const complexVerified = crypto.jwtVerify(complexToken)
console.log(complexVerified.array) // [1, 2, 3]
console.log(complexVerified.nested.level1.level2.level3) // 'deep'
try {
crypto.jwtVerify('invalid.token.format')
} catch (error) {
console.log('Invalid token')
}
try {
crypto.jwtVerify('header.payload.wrongsignature')
} catch (error) {
console.log('Invalid signature')
}
Slug Generation
slug(options?: SlugOptions): string
Generate unique, human-readable slugs using multiple dictionaries.
TypeScript Interface:
interface SlugOptions {
separator?: string
length?: number
}
Options:
separator?: string
- Separator between words (default: '-')length?: number
- Number of words in slug (default: 3)
Available Dictionaries: Uses all available dictionaries automatically: adjectives, colors, animals, names, languages, starWars, and countries for maximum variety and uniqueness.
// Basic slug generation
const slug = crypto.slug()
console.log(slug) // 'happy-blue-elephant'
// Custom separator and length
const customSlug = crypto.slug({
separator: '_',
length: 5,
})
console.log(customSlug) // 'brave_red_tiger_john_french'
// Different separators
const dotSlug = crypto.slug({ separator: '.', length: 4 })
console.log(dotSlug) // 'quick.green.vader.spain'
const spaceSlug = crypto.slug({ separator: ' ', length: 2 })
console.log(spaceSlug) // 'dark purple'
// Generate multiple unique slugs
const slugs = Array.from({ length: 5 }, () => crypto.slug())
console.log(new Set(slugs).size) // 5 (all unique)
// Handle length exceeding available dictionaries
const maxSlug = crypto.slug({ length: 10 })
console.log(maxSlug.split('-').length) // 7 (limited to available dictionaries)
// Single word slug
const singleSlug = crypto.slug({ length: 1 })
console.log(singleSlug) // 'magnificent'
Base64 Utilities
base64Encode(data: string): string
Encode strings to Base64 format.
const data = 'Hello, World!'
const encoded = crypto.base64Encode(data)
console.log(encoded) // 'SGVsbG8sIFdvcmxkIQ=='
const unicode = crypto.base64Encode('🚀 Hello 世界 🌍')
console.log(unicode) // Base64 representation of unicode string
const special = crypto.base64Encode('!@#$%^&*()_+-=[]{}|;:,.<>?`~')
const empty = crypto.base64Encode('')
console.log(empty) // ''
const large = crypto.base64Encode('a'.repeat(1000))
console.log(large.length > 1000) // true
base64Decode(encodedString: string): string
Decode Base64 strings to original format.
const encoded = 'SGVsbG8sIFdvcmxkIQ=='
const decoded = crypto.base64Decode(encoded)
console.log(decoded) // 'Hello, World!'
const original = 'Hello, World! 🚀'
const encoded = crypto.base64Encode(original)
const decoded = crypto.base64Decode(encoded)
console.log(decoded === original) // true
const largeData = 'a'.repeat(1000)
const encodedLarge = crypto.base64Encode(largeData)
const decodedLarge = crypto.base64Decode(encodedLarge)
console.log(decodedLarge === largeData) // true
try {
crypto.base64Decode('invalid base64!')
} catch (error) {
console.log('Invalid base64 string')
}
isBase64Encoded(data: string): boolean
Validate Base64 string format.
console.log(crypto.isBase64Encoded('SGVsbG8sIFdvcmxkIQ==')) // true
console.log(crypto.isBase64Encoded('YW55')) // true (no padding)
console.log(crypto.isBase64Encoded('')) // true (empty)
console.log(crypto.isBase64Encoded('Hello, World!')) // false
console.log(crypto.isBase64Encoded('SGVsbG8@IFdvcmxkIQ==')) // false (invalid char)
const testData = 'Test validation'
const encoded = crypto.base64Encode(testData)
console.log(crypto.isBase64Encoded(encoded)) // true
console.log(crypto.isBase64Encoded(testData)) // false
const testCases = ['Hello', 'SGVsbG8=', '123456', 'MTIzNDU2']
testCases.forEach((test) => {
console.log(`${test}: ${crypto.isBase64Encoded(test)}`)
})
API Key Management
apiKey(options?: ApiKeyOptions): string
Generate secure API keys with HMAC-based authentication.
Options:
prefix?: string
- 3-letter uppercase prefix (default: 'SYN')length?: number
- Hash length in characters, 16-128 (default: 48)
// Generate default API key
const apiKey = crypto.apiKey()
console.log(apiKey) // 'SYN_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0u1v2w3x4y5z6'
// Custom prefix
const devKey = crypto.apiKey({ prefix: 'DEV' })
console.log(devKey) // 'DEV_x1y2z3a4b5c6d7e8f9g0h1i2j3k4l5m6n7o8p9q0r1s2t3u4v5w6'
// Custom length
const longKey = crypto.apiKey({ length: 64 })
console.log(longKey) // 'SYN_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0u1v2w3x4y5z6a7b8c9d0e1f2'
// Custom prefix and length
const customKey = crypto.apiKey({ prefix: 'XYZ', length: 32 })
console.log(customKey) // 'XYZ_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6'
apiKeyVerify(apiKey: string, options?: { prefix?: string }): boolean
Verify the authenticity and format of API keys.
Options:
prefix?: string
- Expected prefix to validate against
// Basic verification
const apiKey = crypto.apiKey()
const isValid = crypto.apiKeyVerify(apiKey)
console.log(isValid) // true
// Verify with custom prefix
const synKey = crypto.apiKey({ prefix: 'SYN' })
const isValidSyn = crypto.apiKeyVerify(synKey)
console.log(isValidSyn) // true
// Verify with prefix validation
const isValidWithPrefix = crypto.apiKeyVerify(synKey, { prefix: 'SYN' })
console.log(isValidWithPrefix) // true
// Prefix mismatch throws error
try {
crypto.apiKeyVerify(synKey, { prefix: 'API' })
} catch (error) {
console.log('API key prefix does not match expected prefix')
}
Security Features:
- HMAC-SHA256 based key generation for cryptographic security
- Entropy validation to prevent weak patterns
- Format validation for prefix and hash structure
- Constant-time comparison for security against timing attacks
- Support for custom prefixes and variable lengths
OTP (One-Time Password)
The library provides comprehensive Time-based One-Time Password (TOTP) functionality compatible with popular authenticator apps like Google Authenticator, Authy, and Microsoft Authenticator.
otpEnrol(options: OTPEnrolOptions): { secret: string; uri: string; qr: string }
Enroll a user for OTP by generating a secret and returning configuration for authenticator apps.
Options:
identifier: string
- Unique identifier for the user (email, username, etc.) - requiredissuer?: string
- The issuer name (app/service name). Defaults to 'Synotech Ai'label?: string
- Label for the OTP entry. Defaults to identifieralgorithm?: 'SHA1' | 'SHA256' | 'SHA512'
- HMAC algorithm. Defaults to 'SHA1'digits?: number
- Number of digits in OTP code. Defaults to 5period?: number
- Time period for TOTP in seconds. Defaults to 120
// Basic enrollment
const enrollment = crypto.otpEnrol({
identifier: 'user@example.com',
})
console.log(enrollment)
// {
// secret: 'JBSWY3DPEHPK3PXP',
// uri: 'otpauth://totp/Synotech Ai:user@example.com?secret=JBSWY3DPEHPK3PXP&issuer=Synotech%20Ai&digits=5&period=120',
// qr: 'otpauth://totp/Synotech Ai:user@example.com?secret=JBSWY3DPEHPK3PXP&issuer=Synotech%20Ai&digits=5&period=120'
// }
// Custom configuration
const customEnrollment = crypto.otpEnrol({
identifier: 'john.doe@company.com',
issuer: 'MyApp',
label: 'John Doe - Production',
algorithm: 'SHA256',
digits: 6,
period: 30,
})
// Use the QR code URI to generate QR codes for users
const qrCodeData = enrollment.uri
// Display this in a QR code for users to scan with their authenticator app
otpIssue(options: OTPIssueOptions): string
Generate a time-based OTP code using the provided secret.
Options:
secret: string
- The base32 encoded secret key - requiredtimestamp?: number
- Optional timestamp for code generation. Defaults to current time
// Generate current OTP code
const code = crypto.otpIssue({
secret: 'JBSWY3DPEHPK3PXP',
})
console.log(code) // '12345' (5-digit code, valid for 120 seconds)
// Generate code for specific timestamp
const historicalCode = crypto.otpIssue({
secret: 'JBSWY3DPEHPK3PXP',
timestamp: 1640995200000,
})
console.log(historicalCode) // '78901'
// Use in authentication flow
const userSecret = enrollment.secret
const currentCode = crypto.otpIssue({ secret: userSecret })
console.log(`Current OTP: ${currentCode}`)
otpVerify(options: OTPVerifyOptions): boolean
Verify a time-based OTP code against the provided secret.
Options:
secret: string
- The base32 encoded secret key - requiredtoken: string
- The OTP code to verify - requiredwindow?: number
- Time window for verification (number of periods). Defaults to 1timestamp?: number
- Optional timestamp for verification. Defaults to current time
// Basic verification
const isValid = crypto.otpVerify({
secret: 'JBSWY3DPEHPK3PXP',
token: '12345',
})
console.log(isValid) // true or false
// Verification with time window (allows codes from adjacent time periods)
const isValidWithWindow = crypto.otpVerify({
secret: 'JBSWY3DPEHPK3PXP',
token: '12345',
window: 2, // Accepts codes from 2 periods before/after current time
})
// Complete authentication flow
const userSecret = 'JBSWY3DPEHPK3PXP'
const userInputCode = '12345'
if (crypto.otpVerify({ secret: userSecret, token: userInputCode })) {
console.log('Authentication successful')
// Grant access
} else {
console.log('Invalid OTP code')
// Deny access
}
// Verify historical code
const historicalVerification = crypto.otpVerify({
secret: 'JBSWY3DPEHPK3PXP',
token: '78901',
timestamp: 1640995200000,
})
Complete OTP Workflow Example:
// 1. User enrollment
const enrollment = crypto.otpEnrol({
identifier: 'user@example.com',
issuer: 'MySecureApp',
})
// 2. Store the secret securely (encrypted in database)
const encryptedSecret = crypto.encrypt(enrollment.secret)
// Save encryptedSecret to user's record
// 3. Show QR code to user for setup
console.log('Scan this QR code with your authenticator app:')
console.log(enrollment.uri)
// 4. During login - user provides OTP code
const userEnteredCode = '12345' // From user input
// 5. Retrieve and decrypt user's secret
const decryptedSecret = crypto.decrypt(encryptedSecret)
// 6. Verify the code
const isAuthenticated = crypto.otpVerify({
secret: decryptedSecret,
token: userEnteredCode,
window: 1, // Allow 1 period tolerance for clock drift
})
if (isAuthenticated) {
// User is authenticated, proceed with login
console.log('OTP verification successful')
} else {
// Authentication failed
console.log('Invalid OTP code')
}
Security Features:
- RFC 6238 compliant TOTP implementation
- Cryptographically secure secret generation
- Configurable time windows for clock drift tolerance
- Support for multiple hash algorithms (SHA1, SHA256, SHA512)
- Base32 encoded secrets for compatibility with authenticator apps
- Customizable code length and validity periods
Testing
Run the complete test suite:
npm test
Tests cover:
- Constructor validation and environment variable handling
- Encryption/decryption operations
- JWT token management
- API key generation and verification
- OTP enrollment, generation, and verification
- Digital signature operations
- Key generation and validation
Security Features
- AES-256-GCM: Authenticated encryption with integrity verification
- Internal Entropy Generation: Built-in cryptographically secure random number generation using Node.js
crypto.randomBytes()
- Dynamic Key Generation: Fresh entropy generated on-demand for each operation
- Key Validation: Automatic validation of key length and format
- Environment Security: Secure key management via environment variables
- Buffer Safety: Proper buffer allocation and cleanup
- Self-contained Security: No external file dependencies for entropy generation
Development
Demo Interface
# Start interactive demo
npm run demo
# Generate environment keys
npm run demo:keys
# Show usage examples
npm run demo:show
Key Generation Script
# Generate new .env file
node generate.js generate
# Show new keys without saving
node generate.js show
# Show help
node generate.js help
Demo Script
# Run usage demonstration
node dev.js
Project Structure
├── index.ts # Main Cryptography class with internal entropy generation
├── __tests__/ # Test suite
│ ├── __config.ts # Test configuration
│ ├── __constructor.spec.ts
│ ├── __encrypt.spec.ts
│ └── __jwt.spec.ts
├── generate.js # Key generation utility
├── dev.js # Usage demonstration
└── .env # Environment variables (AES & HMAC keys only)
License
ISC License
Contributing
- Fork the repository
- Create a feature branch
- Add tests for new functionality
- Ensure all tests pass:
npm test
- Submit a pull request
Security Notice
⚠️ Important: Never commit cryptographic keys to version control. Always use environment variables or secure key management systems in production.