@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
Markdown
# 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.