A secure, easy-to-use encryption library and CLI tool for Node.js and browser environments with built-in cryptographic best practices.
- Automatic random salt generation for each encryption operation
- Automatic random IV/nonce generation for each encryption operation
- No IV/nonce reuse - each encryption produces unique ciphertext even for identical plaintext
- PBKDF2 key derivation with 100,000 iterations
- Authenticated encryption with AES-GCM and ChaCha20-Poly1305
- Secure data format that packages salt, IV, and ciphertext together
- Multiple encryption algorithms:
- AES-GCM for robust symmetric encryption
- ChaCha20-Poly1305 for high-performance encryption
- Text encoding options for multi-language support
- File encryption capabilities
- Line-by-line text file encryption
- Simple API with security built-in
- CLI tool for command-line usage
npm install easy-cipher-mate
yarn add easy-cipher-mate
easy-cipher-mate encrypt-file -i input.txt -o output.txt -p yourpassword -a aes-gcm
easy-cipher-mate decrypt-file -i encrypted.txt -o decrypted.txt -p yourpassword -a aes-gcm
easy-cipher-mate encrypt-text-file -f input.txt -p yourpassword -a aes-gcm -e utf-8
easy-cipher-mate decrypt-text-file -f encrypted.txt -p yourpassword -a aes-gcm -e utf-8
Options:
-i, --input <path>
: Input file path (required)-o, --output <path>
: Output file path (required)-f, --file <path>
: Text file path (required)-p, --password <string>
: Encryption/decryption password (required)-a, --algorithm <string>
: Algorithm - 'aes-gcm' (default) or 'chacha20-poly1305'-e, --encoding <string>
: Text encoding - 'utf-8' (default), 'ascii', 'utf16le', 'base64', 'hex', 'latin1', or 'binary'
import {
AESGCMEncryption,
AESGCMEncryptionConfig,
EncryptionService
} from 'easy-cipher-mate';
// Create encryption instance and configuration
const encryption = new AESGCMEncryption();
const config = new AESGCMEncryptionConfig('your-secure-password');
const service = new EncryptionService(encryption, config);
// Encrypt text
const plaintext = 'Hello, World!';
const encrypted = await service.encryptText(plaintext);
// Decrypt text
const decrypted = await service.decryptText(encrypted.data);
console.log(decrypted); // 'Hello, World!'
// π Security: Each encryption produces different ciphertext!
const encrypted1 = await service.encryptText(plaintext);
const encrypted2 = await service.encryptText(plaintext);
console.log(encrypted1.data !== encrypted2.data); // true - different ciphertext!
import {
ChaCha20Poly1305Encryption,
ChaCha20Poly1305EncryptionConfig,
EncryptionService
} from 'easy-cipher-mate';
const encryption = new ChaCha20Poly1305Encryption();
const config = new ChaCha20Poly1305EncryptionConfig('your-secure-password');
const service = new EncryptionService(encryption, config);
const encrypted = await service.encryptText('Secret message');
const decrypted = await service.decryptText(encrypted.data);
import { AESGCMEncryption, AESGCMEncryptionConfig } from 'easy-cipher-mate';
const encryption = new AESGCMEncryption();
// Configure with specific text encoding
const config = new AESGCMEncryptionConfig('my-password', 'base64');
// Encrypt text with base64 encoding
const encrypted = await encryption.encryptText('Secret message', config);
const decrypted = await encryption.decryptText(encrypted.data, config);
// Override encoding for specific operations
const hexEncrypted = await encryption.encryptText('Another message', config, 'hex');
const hexDecrypted = await encryption.decryptText(hexEncrypted.data, config, 'hex');
import { AESGCMEncryption, AESGCMEncryptionConfig } from 'easy-cipher-mate';
const encryption = new AESGCMEncryption();
const config = new AESGCMEncryptionConfig('my-password');
// Encrypt Chinese text
const chineseText = 'δ½ ε₯½οΌδΈη';
const encryptedChinese = await encryption.encryptText(chineseText, config);
const decryptedChinese = await encryption.decryptText(encryptedChinese.data, config);
// Encrypt Japanese text with UTF-16LE encoding
const japaneseText = 'γγγ«γ‘γ―δΈη';
const encryptedJapanese = await encryption.encryptText(japaneseText, config, 'utf16le');
const decryptedJapanese = await encryption.decryptText(encryptedJapanese.data, config, 'utf16le');
// Encrypt emoji and mixed content
const emojiText = 'π Hello! π δ½ ε₯½ γγγ«γ‘γ―';
const encryptedEmoji = await encryption.encryptText(emojiText, config);
const decryptedEmoji = await encryption.decryptText(encryptedEmoji.data, config);
import { AESGCMEncryption, AESGCMEncryptionConfig, EncryptionService } from 'easy-cipher-mate';
import { readFileSync, writeFileSync } from 'fs';
const encryption = new AESGCMEncryption();
const config = new AESGCMEncryptionConfig('my-password');
const service = new EncryptionService(encryption, config);
// Encrypt a file
const fileBuffer = readFileSync('document.pdf');
const arrayBuffer = fileBuffer.buffer.slice(fileBuffer.byteOffset, fileBuffer.byteOffset + fileBuffer.byteLength);
const encryptedResult = await encryption.encryptFile(arrayBuffer, config);
writeFileSync('document.pdf.encrypted', Buffer.from(encryptedResult.data));
// Decrypt the file
const encryptedFileBuffer = readFileSync('document.pdf.encrypted');
const encryptedArrayBuffer = encryptedFileBuffer.buffer.slice(
encryptedFileBuffer.byteOffset,
encryptedFileBuffer.byteOffset + encryptedFileBuffer.byteLength
);
const decryptedBuffer = await encryption.decryptFile(encryptedArrayBuffer, config);
writeFileSync('document.pdf.decrypted', Buffer.from(decryptedBuffer));
// Simplified file operations with EncryptionService
const encrypted = await service.encryptFileByName('document.pdf');
await service.decryptFileByName(encrypted, 'document.pdf.decrypted');
import { AESGCMEncryption, AESGCMEncryptionConfig, EncryptionService } from 'easy-cipher-mate';
import { readFileSync, writeFileSync } from 'fs';
const encryption = new AESGCMEncryption();
const config = new AESGCMEncryptionConfig('my-password');
const service = new EncryptionService(encryption, config);
// Read and encrypt each line
const content = readFileSync('document.txt', 'utf-8');
const lines = content.split(/\r?\n/);
const encryptedLines = await Promise.all(
lines.map(async line => {
if (line.trim() === '') return line;
const result = await service.encryptText(line);
return Buffer.from(result.data).toString('base64');
})
);
writeFileSync('document.txt.encrypted', encryptedLines.join('\n'));
// Decrypt each line
const encryptedContent = readFileSync('document.txt.encrypted', 'utf-8');
const encryptedLinesArray = encryptedContent.split(/\r?\n/);
const decryptedLines = await Promise.all(
encryptedLinesArray.map(async line => {
if (line.trim() === '') return line;
const buffer = Buffer.from(line, 'base64');
return await service.decryptText(buffer);
})
);
writeFileSync('document.txt.decrypted', decryptedLines.join('\n'));
class AESGCMEncryption {
encryptText(plaintext: string, config: IAESGCMEncryptionConfig, encoding?: TextEncoding): Promise<EncryptionResult>
decryptText(encryptedData: ArrayBuffer, config: IAESGCMEncryptionConfig, encoding?: TextEncoding): Promise<string>
encryptFile(fileBuffer: ArrayBuffer, config: IAESGCMEncryptionConfig): Promise<EncryptionResult>
decryptFile(encryptedBuffer: ArrayBuffer, config: IAESGCMEncryptionConfig): Promise<ArrayBuffer>
}
class ChaCha20Poly1305Encryption {
encryptText(plaintext: string, config: IChaCha20Poly1305EncryptionConfig, encoding?: TextEncoding): Promise<EncryptionResult>
decryptText(encryptedData: ArrayBuffer, config: IChaCha20Poly1305EncryptionConfig, encoding?: TextEncoding): Promise<string>
encryptFile(fileBuffer: ArrayBuffer, config: IChaCha20Poly1305EncryptionConfig): Promise<EncryptionResult>
decryptFile(encryptedBuffer: ArrayBuffer, config: IChaCha20Poly1305EncryptionConfig): Promise<ArrayBuffer>
}
class AESGCMEncryptionConfig {
constructor(password: string, textEncoding?: TextEncoding)
}
class ChaCha20Poly1305EncryptionConfig {
constructor(password: string, textEncoding?: TextEncoding)
}
A wrapper class that simplifies encryption operations:
class EncryptionService<TAlgorithm, TConfig> {
encryptText(plaintext: string, encoding?: TextEncoding): Promise<EncryptionResult>
decryptText(encryptedData: ArrayBuffer, encoding?: TextEncoding): Promise<string>
encryptFile(fileBuffer: ArrayBuffer, encoding?: TextEncoding): Promise<EncryptionResult>
decryptFile(encryptedBuffer: ArrayBuffer, encoding?: TextEncoding): Promise<ArrayBuffer>
encryptFileByName(fileName: string): Promise<EncryptionResult>
decryptFileByName(encryptedResult: EncryptionResult, fileName: string): Promise<void>
}
utf-8
(default): Unicode encoding, supports all languagesascii
: ASCII encoding (7-bit, basic English characters only)utf16le
: UTF-16 Little Endian encodingbase64
: Base64 encodinghex
: Hexadecimal encodinglatin1
/binary
: Latin-1 encoding (single byte per character)
This library implements cryptographic best practices automatically:
- Random Salt Generation: Each encryption generates a new random 16-byte salt
- Random IV/Nonce Generation: Each encryption generates a new random IV (12 bytes for AES-GCM) or nonce (12 bytes for ChaCha20-Poly1305)
- No Key/IV Reuse: The combination of key and IV/nonce is never reused
- Strong Key Derivation: PBKDF2 with 100,000 iterations and SHA-256
- Authenticated Encryption: Both algorithms provide built-in authentication
- Secure Data Format: Salt, IV/nonce, and ciphertext are packaged together
The encrypted output follows this format:
- AES-GCM:
[16-byte salt][12-byte IV][ciphertext with auth tag]
- ChaCha20-Poly1305:
[16-byte salt][12-byte nonce][ciphertext][16-byte auth tag]
Feel free to open issues or pull requests. For more information on how to contribute, please visit the contribution guidelines.
MIT License. See LICENSE for more details.
If you're upgrading from v1.x, note that the API has been simplified for better security:
Old (v1.x) - INSECURE:
// β Old way - manually setting salt/IV (security risk!)
const config = new AESGCMEncryptionConfigFromEnv(password, salt, iv);
New (v2.x) - SECURE:
// β
New way - automatic random salt/IV generation
const config = new AESGCMEncryptionConfig(password);
The new version automatically generates random salt and IV for each encryption, eliminating the security risks of the previous approach.