UNPKG

@hiprax/crypto

Version:

High-security encryption/decryption library using AES-256-GCM and Argon2id

632 lines (440 loc) โ€ข 18.7 kB
# Crypto ๐Ÿ” **High-security encryption/decryption library** using AES-256-GCM and Argon2id for Node.js applications with full TypeScript support. [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) [![TypeScript](https://img.shields.io/badge/TypeScript-5.8.3-blue.svg)](https://www.typescriptlang.org/) [![Node.js](https://img.shields.io/badge/Node.js-18+-green.svg)](https://nodejs.org/) ## โœจ Features - ๐Ÿ” **AES-256-GCM** authenticated encryption - ๐Ÿ”‘ **Argon2id** memory-hard key derivation - ๐Ÿ“ **File streaming** for large files - ๐Ÿ›ก๏ธ **Memory-safe** operations with secure clearing - โœ… **Strong password** validation with detailed feedback - ๐Ÿ”„ **Cross-platform** compatibility - ๐Ÿ“ **Full TypeScript** support with strict typing - ๐Ÿงช **Comprehensive testing** with 80%+ coverage - ๐Ÿš€ **Modern ES modules** with tree-shaking support - ๐Ÿ”’ **Security-focused** with constant-time comparisons - ๐Ÿ”‘ **Default passphrase** support for simplified usage ## ๐Ÿ“ฆ Installation ```bash npm install @hiprax/crypto ``` ## ๐Ÿš€ Quick Start ### Basic Usage #### Asynchronous Operations (Recommended) ```typescript import { CryptoManager } from '@hiprax/crypto'; const crypto = new CryptoManager(); // Encrypt text const encrypted = await crypto.encryptText( 'Hello World', 'MySecureP@ssw0rd123!' ); console.log('Encrypted:', encrypted); // Decrypt text const decrypted = await crypto.decryptText(encrypted, 'MySecureP@ssw0rd123!'); console.log('Decrypted:', decrypted); ``` #### Synchronous Operations For scenarios where you need synchronous operations (note: uses PBKDF2 instead of Argon2id for key derivation): ```typescript import { CryptoManager } from '@hiprax/crypto'; const crypto = new CryptoManager(); // Encrypt text synchronously const encrypted = crypto.encryptTextSync('Hello World', 'MySecureP@ssw0rd123!'); console.log('Encrypted:', encrypted); // Decrypt text synchronously const decrypted = crypto.decryptTextSync(encrypted, 'MySecureP@ssw0rd123!'); console.log('Decrypted:', decrypted); ``` ### Using Default Passphrase You can set a default passphrase when creating the CryptoManager instance, which allows you to encrypt and decrypt without specifying a password each time: ```typescript import { CryptoManager } from '@hiprax/crypto'; // Create instance with default passphrase const crypto = new CryptoManager({ defaultPassphrase: 'MySecureP@ssw0rd123!', }); // Encrypt text without specifying password const encrypted = await crypto.encryptText('Hello World'); console.log('Encrypted:', encrypted); // Decrypt text without specifying password const decrypted = await crypto.decryptText(encrypted); console.log('Decrypted:', decrypted); // You can still override with a custom password const encryptedWithCustom = await crypto.encryptText( 'Hello World', 'CustomP@ssw0rd456!' ); ``` ### File Encryption #### Asynchronous File Operations (Recommended) ```typescript import { CryptoManager } from '@hiprax/crypto'; const crypto = new CryptoManager(); // Encrypt file await crypto.encryptFile('input.txt', 'output.enc', 'MySecureP@ssw0rd123!'); // Decrypt file await crypto.decryptFile('output.enc', 'decrypted.txt', 'MySecureP@ssw0rd123!'); ``` #### Synchronous File Operations For scenarios where you need synchronous file operations (note: uses PBKDF2 instead of Argon2id for key derivation): ```typescript import { CryptoManager } from '@hiprax/crypto'; const crypto = new CryptoManager(); // Encrypt file synchronously crypto.encryptFileSync('input.txt', 'output.enc', 'MySecureP@ssw0rd123!'); // Decrypt file synchronously crypto.decryptFileSync('output.enc', 'decrypted.txt', 'MySecureP@ssw0rd123!'); ``` ### File Encryption with Default Passphrase #### Asynchronous Operations ```typescript import { CryptoManager } from '@hiprax/crypto'; // Create instance with default passphrase const crypto = new CryptoManager({ defaultPassphrase: 'MySecureP@ssw0rd123!', }); // Encrypt file without specifying password await crypto.encryptFile('input.txt', 'output.enc'); // Decrypt file without specifying password await crypto.decryptFile('output.enc', 'decrypted.txt'); // You can still override with a custom password await crypto.encryptFile('input.txt', 'output.enc', 'CustomP@ssw0rd456!'); ``` #### Synchronous Operations ```typescript import { CryptoManager } from '@hiprax/crypto'; // Create instance with default passphrase const crypto = new CryptoManager({ defaultPassphrase: 'MySecureP@ssw0rd123!', }); // Encrypt file synchronously without specifying password crypto.encryptFileSync('input.txt', 'output.enc'); // Decrypt file synchronously without specifying password crypto.decryptFileSync('output.enc', 'decrypted.txt'); // You can still override with a custom password crypto.encryptFileSync('input.txt', 'output.enc', 'CustomP@ssw0rd456!'); ``` ### Custom Configuration ```typescript import { CryptoManager } from '@hiprax/crypto'; const crypto = new CryptoManager({ memoryCost: 2 ** 18, // 256MB (ultra security) timeCost: 4, // Higher time cost parallelism: 2, // Use 2 threads aad: 'my-app-v1', // Custom AAD }); console.log('Security Level:', crypto.getSecurityLevel()); // 'ultra' ``` ## ๐Ÿ“š API Reference ### CryptoManager The main class for encryption/decryption operations. #### Constructor ```typescript const crypto = new CryptoManager(options?: CryptoManagerOptions); ``` **Options:** - `memoryCost` (number): Argon2 memory cost (default: 65536) - `timeCost` (number): Argon2 time cost (default: 3) - `parallelism` (number): Argon2 parallelism (default: 1) - `aad` (string): Custom Additional Authenticated Data (default: 'secure-crypto-tool-v2') - `defaultPassphrase` (string): Default passphrase to use when no password is provided to encryption/decryption methods #### Methods ##### `encryptText(text: string, password?: string): Promise<string>` Encrypts text with a password. If no password is provided and a default passphrase is set, the default passphrase will be used. ```typescript const encrypted = await crypto.encryptText( 'Hello World', 'MySecureP@ssw0rd123!' ); // Returns: base64 encoded string // With default passphrase const crypto = new CryptoManager({ defaultPassphrase: 'MySecureP@ssw0rd123!' }); const encrypted = await crypto.encryptText('Hello World'); ``` ##### `decryptText(encryptedText: string, password?: string): Promise<string>` Decrypts text with a password. If no password is provided and a default passphrase is set, the default passphrase will be used. ```typescript const decrypted = await crypto.decryptText(encrypted, 'MySecureP@ssw0rd123!'); // Returns: original text // With default passphrase const crypto = new CryptoManager({ defaultPassphrase: 'MySecureP@ssw0rd123!' }); const decrypted = await crypto.decryptText(encrypted); ``` ##### `encryptTextSync(text: string, password?: string): string` Synchronous version of text encryption. Uses PBKDF2 for key derivation instead of Argon2id for synchronous operation. ```typescript const encrypted = crypto.encryptTextSync('Hello World', 'MySecureP@ssw0rd123!'); // Returns: base64 encoded string // With default passphrase const crypto = new CryptoManager({ defaultPassphrase: 'MySecureP@ssw0rd123!' }); const encrypted = crypto.encryptTextSync('Hello World'); ``` ##### `decryptTextSync(encryptedText: string, password?: string): string` Synchronous version of text decryption. Uses PBKDF2 for key derivation instead of Argon2id for synchronous operation. ```typescript const decrypted = crypto.decryptTextSync(encrypted, 'MySecureP@ssw0rd123!'); // Returns: original text // With default passphrase const crypto = new CryptoManager({ defaultPassphrase: 'MySecureP@ssw0rd123!' }); const decrypted = crypto.decryptTextSync(encrypted); ``` ##### `encryptFile(inputPath: string, outputPath: string, password?: string, progressCallback?: ProgressCallback): Promise<void>` Encrypts a file with a password. If no password is provided and a default passphrase is set, the default passphrase will be used. ```typescript await crypto.encryptFile('input.txt', 'output.enc', 'MySecureP@ssw0rd123!'); // With default passphrase const crypto = new CryptoManager({ defaultPassphrase: 'MySecureP@ssw0rd123!' }); await crypto.encryptFile('input.txt', 'output.enc'); ``` ##### `decryptFile(inputPath: string, outputPath: string, password?: string, progressCallback?: ProgressCallback): Promise<void>` Decrypts a file with a password. If no password is provided and a default passphrase is set, the default passphrase will be used. ```typescript await crypto.decryptFile('output.enc', 'decrypted.txt', 'MySecureP@ssw0rd123!'); // With default passphrase const crypto = new CryptoManager({ defaultPassphrase: 'MySecureP@ssw0rd123!' }); await crypto.decryptFile('output.enc', 'decrypted.txt'); ``` ##### `encryptFileSync(inputPath: string, outputPath: string, password?: string): void` Synchronous version of file encryption. Uses PBKDF2 for key derivation instead of Argon2id for synchronous operation. ```typescript crypto.encryptFileSync('input.txt', 'output.enc', 'MySecureP@ssw0rd123!'); // With default passphrase const crypto = new CryptoManager({ defaultPassphrase: 'MySecureP@ssw0rd123!' }); crypto.encryptFileSync('input.txt', 'output.enc'); ``` ##### `decryptFileSync(inputPath: string, outputPath: string, password?: string): void` Synchronous version of file decryption. Uses PBKDF2 for key derivation instead of Argon2id for synchronous operation. ```typescript crypto.decryptFileSync('output.enc', 'decrypted.txt', 'MySecureP@ssw0rd123!'); // With default passphrase const crypto = new CryptoManager({ defaultPassphrase: 'MySecureP@ssw0rd123!' }); crypto.decryptFileSync('output.enc', 'decrypted.txt'); ``` ##### `validatePassword(password: string): boolean` Validates password strength. ```typescript const isValid = crypto.validatePassword('MySecureP@ssw0rd123!'); // Returns: boolean ``` ##### `generateSecureRandom(length: number): Buffer` Generates cryptographically secure random bytes. ```typescript const random = crypto.generateSecureRandom(32); // Returns: Buffer ``` ##### `deriveKeySync(password: string, salt: Buffer): Buffer` Synchronous version of key derivation using PBKDF2 instead of Argon2id. ```typescript const salt = crypto.generateSecureRandom(32); const key = crypto.deriveKeySync('MySecureP@ssw0rd123!', salt); // Returns: Buffer ``` ##### `getParameters(): EncryptionParameters` Gets current encryption parameters. ```typescript const params = crypto.getParameters(); // Returns: object with algorithm details ``` ##### `getSecurityLevel(): SecurityLevel` Gets security level based on configuration. ```typescript const level = crypto.getSecurityLevel(); // Returns: 'low' | 'medium' | 'high' | 'ultra' ``` ##### `hasDefaultPassphrase(): boolean` Checks if a default passphrase is configured. ```typescript const hasDefault = crypto.hasDefaultPassphrase(); // Returns: boolean indicating if default passphrase is set ``` ### Utility Functions Additional utility functions are also exported: ```typescript import { validateFile, validatePath, generateRandomString, validatePasswordStrength, generateUUID, sha256, generateRandomHex, secureStringCompare, formatFileSize, isTextFile, sanitizeFilename, createBackupPath, isValidBase64, createProgressBar, sleep, retryWithBackoff, getFileInfo, } from '@hiprax/crypto'; // Validate if file exists and is accessible const fileValidation = await validateFile('path/to/file.txt'); // Validate if path is valid for writing const pathValidation = validatePath('path/to/output.txt'); // Generate secure random string const randomString = generateRandomString(32); // Validate password strength with detailed feedback const passwordCheck = validatePasswordStrength('MyPassword123!'); console.log('Score:', passwordCheck.score); // 0-5 console.log('Feedback:', passwordCheck.feedback); // Array of suggestions // Generate UUID const uuid = generateUUID(); // Hash string with SHA-256 const hash = sha256('hello world'); // Generate random hex string const hex = generateRandomHex(16); // Secure string comparison (constant time) const isEqual = secureStringCompare('secret', 'secret'); // Format file size const size = formatFileSize(1024 * 1024); // "1 MB" // Check if file is text file const isText = isTextFile('document.txt'); // Sanitize filename const safeName = sanitizeFilename('file<name>.txt'); // "file_name_.txt" // Create backup path const backupPath = createBackupPath('file.txt'); // "file_2024-01-01T12-00-00.backup.txt" // Validate base64 const isValid = isValidBase64('SGVsbG8gV29ybGQ='); // Create progress bar const progress = createProgressBar(50, 100); // "[โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘] 50%" // Sleep for specified time await sleep(1000); // Sleep for 1 second // Retry with exponential backoff const result = await retryWithBackoff( async () => { // Some async operation that might fail return await someOperation(); }, { maxRetries: 3, baseDelay: 1000 } ); // Get file information const fileInfo = await getFileInfo('path/to/file.txt'); console.log('Size:', fileInfo.size); console.log('Extension:', fileInfo.extension); console.log('Is Text:', fileInfo.isTextFile); ``` ## ๐Ÿ”ง Configuration ### Asynchronous vs Synchronous Operations The library provides both asynchronous and synchronous versions of encryption/decryption operations: #### Asynchronous Operations (Recommended) - Use **Argon2id** for key derivation (more secure) - Better for performance and scalability - Non-blocking operations - Methods: `encryptText()`, `decryptText()`, `encryptFile()`, `decryptFile()` #### Synchronous Operations - Use **PBKDF2** for key derivation (less secure but synchronous) - Blocking operations - Useful for simple scripts or when async/await is not available - Methods: `encryptTextSync()`, `decryptTextSync()`, `encryptFileSync()`, `decryptFileSync()` **Note**: Synchronous operations use PBKDF2 with 100,000 iterations for security, but Argon2id is still recommended for production use. **Important**: Synchronous and asynchronous functions are not compatible with each other due to different key derivation methods. Always use the same type (sync or async) for both encryption and decryption. ### Security Levels The library supports different security levels based on Argon2 parameters: - **Low**: `memoryCost: 2^12, timeCost: 1` (Fast, less secure) - **Medium**: `memoryCost: 2^14, timeCost: 2` (Balanced) - **High**: `memoryCost: 2^16, timeCost: 3` (Default, secure) - **Ultra**: `memoryCost: 2^18, timeCost: 4` (Maximum security) ### Password Requirements Passwords must meet the following criteria: - Minimum 8 characters - At least one uppercase letter - At least one lowercase letter - At least one number - At least one special character ## ๐Ÿ›ก๏ธ Security Features ### Cryptographic Security - **AES-256-GCM**: Authenticated encryption with Galois/Counter Mode - **Argon2id**: Memory-hard key derivation function (winner of Password Hashing Competition) - **Secure Random**: Uses Node.js `crypto.randomBytes()` for all random generation - **Constant-time Operations**: Secure string comparison to prevent timing attacks ### Memory Security - **Secure Clearing**: Sensitive data is zeroed from memory after use - **No Memory Leaks**: Proper cleanup of cryptographic materials - **Buffer Management**: Safe handling of cryptographic buffers ### Input Validation - **Path Sanitization**: Prevents path traversal attacks - **Type Safety**: Full TypeScript support prevents type-related vulnerabilities - **Parameter Validation**: Comprehensive input validation with detailed error messages ## ๐Ÿงช Testing Run the test suite: ```bash npm test ``` Run tests with coverage: ```bash npm run test:coverage ``` Run tests in watch mode: ```bash npm run test:watch ``` ## ๐Ÿ” Error Handling The library uses custom error types for better error handling: ```typescript import { CryptoError, CryptoErrorType } from '@hiprax/crypto'; try { await crypto.encryptText('', ''); } catch (error) { if (error instanceof CryptoError) { console.log('Error Type:', error.type); console.log('Error Code:', error.code); console.log('Message:', error.message); } } ``` ### Error Types - `INVALID_PASSWORD`: Password-related errors - `INVALID_INPUT`: Invalid input parameters - `ENCRYPTION_FAILED`: Encryption operation failures - `DECRYPTION_FAILED`: Decryption operation failures - `FILE_ERROR`: File system errors - `MEMORY_ERROR`: Memory-related errors - `VALIDATION_ERROR`: Validation failures ## ๐Ÿ“ฆ Development ### Building ```bash npm run build ``` ### Linting ```bash npm run lint npm run lint:fix ``` ### Formatting ```bash npm run format ``` ### Type Checking ```bash npm run type-check ``` ## ๐Ÿค Contributing 1. Fork the repository 2. Create a feature branch 3. Make your changes 4. Add tests for new functionality 5. Ensure all tests pass 6. Submit a pull request ## ๐Ÿ“„ License MIT License - see [LICENSE](LICENSE) file for details. ## ๐Ÿ”— Links - [NPM Package](https://www.npmjs.com/package/@hiprax/crypto) - [GitHub Repository](https://github.com/Hiprax/crypto) - [Issue Tracker](https://github.com/Hiprax/crypto/issues) ## โš ๏ธ Security Notice This library is designed for security but should be used as part of a comprehensive security strategy. Always: - Use strong, unique passwords - Keep your dependencies updated - Follow security best practices - Consider additional security measures for critical applications ## ๐Ÿ†˜ Support For support, please: 1. Check the [documentation](https://github.com/Hiprax/crypto#readme) 2. Search [existing issues](https://github.com/Hiprax/crypto/issues) 3. Create a new issue if needed --- **Made with โค๏ธ for secure applications**