UNPKG

@synotech/crypto

Version:

Comprehensive cryptography library with Web3 integration, supporting symmetric/asymmetric encryption, digital signatures, JWT tokens, blockchain address generation, and secure key management

1,037 lines (759 loc) 29.1 kB
# Cryptography A comprehensive TypeScript cryptography library providing secure encryption, digital signatures, JWT token management, and Web3-compatible cryptographic operations. ## Features - **[AES-256-GCM Encryption](#encryption-methods)**: Secure two-way encryption and decryption - **[Digital Signatures](#digital-signatures)**: RSA and ECC-based signature generation and verification - **[JWT Token Management](#jwt-token-management)**: Token creation, validation, and verification - **[API Key Management](#api-key-management)**: Secure API key generation and verification with HMAC - **[OTP (One-Time Password)](#otp-one-time-password)**: TOTP-based authentication with configurable parameters - **[Web3 Compatibility](#cryptographic-address-generation)**: Blockchain address generation and signature schemes - **[Key Management](#key-pair-generation)**: Secure key generation and environment-based configuration - **[Hash Functions](#password-hashing)**: SHA-256, SHA-512, and HMAC operations - **[Slug Generation](#slug-generation)**: Human-readable unique identifiers with multiple dictionaries - **[Encoding Utilities](#base64-utilities)**: Base64 encoding/decoding and validation ## Installation ```bash yarn install ``` ## Environment Setup ### Quick Start Generate secure cryptographic keys: ```bash # 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: ```env 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) ```typescript 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 ```typescript const crypto = new Cryptography({ encryptKey: 'your64hexencryptionkey...', encryptKeySingle: 'your64hexsigningkey...', }) ``` ### Mixed Configuration ```typescript 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: ```bash # 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. ```typescript 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 uses `CRYPTO_AES_ENCRYPTION_KEY` env var - `encryptKeySingle?: string` - HMAC signing key (64 hex chars) or uses `CRYPTO_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) ```typescript 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, alphanumeric - `strong_pw` - 15 characters, alphanumeric + special - `ft_knox_pw` - 30 characters, alphanumeric + special - `ci_key` - 32 characters, alphanumeric - `160_wpa` - 20 characters, alphanumeric + special - `504_wpa` - 63 characters, alphanumeric + special - `64_wep` - 5 characters, hex only - `128_wep` - 13 characters, hex only - `152_wep` - 16 characters, hex only - `256_wep` - 29 characters, hex only ```typescript 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. ```typescript 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. ```typescript 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. ```typescript 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). ```typescript 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. ```typescript const signature = crypto.signature() console.log(signature.split(':').length) // 3 components ``` #### `signatureVerify(signature: string): boolean` Verify digital signature authenticity. ```typescript 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. ```typescript 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. ```typescript 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). ```typescript 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. ```typescript 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. ```typescript 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. ```typescript 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. ```typescript 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:** ```typescript 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. ```typescript // 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. ```typescript 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. ```typescript 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. ```typescript 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) ```typescript // 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 ```typescript // 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.) - **required** - `issuer?: string` - The issuer name (app/service name). Defaults to 'Synotech Ai' - `label?: string` - Label for the OTP entry. Defaults to identifier - `algorithm?: 'SHA1' | 'SHA256' | 'SHA512'` - HMAC algorithm. Defaults to 'SHA1' - `digits?: number` - Number of digits in OTP code. Defaults to 5 - `period?: number` - Time period for TOTP in seconds. Defaults to 120 ```typescript // 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 - **required** - `timestamp?: number` - Optional timestamp for code generation. Defaults to current time ```typescript // 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 - **required** - `token: string` - The OTP code to verify - **required** - `window?: number` - Time window for verification (number of periods). Defaults to 1 - `timestamp?: number` - Optional timestamp for verification. Defaults to current time ```typescript // 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:** ```typescript // 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: ```bash 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 ```bash # Start interactive demo npm run demo # Generate environment keys npm run demo:keys # Show usage examples npm run demo:show ``` ### Key Generation Script ```bash # 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 ```bash # 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 1. Fork the repository 2. Create a feature branch 3. Add tests for new functionality 4. Ensure all tests pass: `npm test` 5. 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.