easy-cipher-mate
Version:
A CLI and programmatic tool for encryption/decryption supporting AES-GCM and ChaCha20-Poly1305 algorithms, with text encoding options and line-by-line text file processing.
339 lines (254 loc) β’ 11.8 kB
Markdown
# easy-cipher-mate
A secure, easy-to-use encryption library and CLI tool for Node.js and browser environments with built-in cryptographic best practices.
## π Security Features
- **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
## π Features
- 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
## π¦ Installation
### With npm
```bash
npm install easy-cipher-mate
```
### With yarn
```bash
yarn add easy-cipher-mate
```
## π₯οΈ CLI Usage
### Encrypt a file
```bash
easy-cipher-mate encrypt-file -i input.txt -o output.txt -p yourpassword -a aes-gcm
```
### Decrypt a file
```bash
easy-cipher-mate decrypt-file -i encrypted.txt -o decrypted.txt -p yourpassword -a aes-gcm
```
### Encrypt a text file line by line
```bash
easy-cipher-mate encrypt-text-file -f input.txt -p yourpassword -a aes-gcm -e utf-8
```
### Decrypt a text file line by line
```bash
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'
## π» Programmatic Usage
### Basic Text Encryption
```typescript
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!
```
### ChaCha20-Poly1305 Encryption
```typescript
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);
```
### Working with Different Text Encodings
```typescript
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');
```
### Multi-language Support
```typescript
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);
```
### File Encryption
```typescript
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');
```
### Line-by-Line Text File Encryption
```typescript
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'));
```
## π§ API Reference
### Encryption Algorithms
#### AESGCMEncryption
```typescript
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>
}
```
#### ChaCha20Poly1305Encryption
```typescript
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>
}
```
### Configuration Classes
#### AESGCMEncryptionConfig
```typescript
class AESGCMEncryptionConfig {
constructor(password: string, textEncoding?: TextEncoding)
}
```
#### ChaCha20Poly1305EncryptionConfig
```typescript
class ChaCha20Poly1305EncryptionConfig {
constructor(password: string, textEncoding?: TextEncoding)
}
```
### EncryptionService
A wrapper class that simplifies encryption operations:
```typescript
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>
}
```
## π Supported Text Encodings
- `utf-8` (default): Unicode encoding, supports all languages
- `ascii`: ASCII encoding (7-bit, basic English characters only)
- `utf16le`: UTF-16 Little Endian encoding
- `base64`: Base64 encoding
- `hex`: Hexadecimal encoding
- `latin1`/`binary`: Latin-1 encoding (single byte per character)
## π Security Best Practices
This library implements cryptographic best practices automatically:
1. **Random Salt Generation**: Each encryption generates a new random 16-byte salt
2. **Random IV/Nonce Generation**: Each encryption generates a new random IV (12 bytes for AES-GCM) or nonce (12 bytes for ChaCha20-Poly1305)
3. **No Key/IV Reuse**: The combination of key and IV/nonce is never reused
4. **Strong Key Derivation**: PBKDF2 with 100,000 iterations and SHA-256
5. **Authenticated Encryption**: Both algorithms provide built-in authentication
6. **Secure Data Format**: Salt, IV/nonce, and ciphertext are packaged together
### Data Format
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]`
## π€ Contributing
Feel free to open issues or pull requests. For more information on how to contribute, please visit the [contribution guidelines](CONTRIBUTING.md).
## π License
MIT License. See [LICENSE](LICENSE) for more details.
---
## π¨ Migration from v1.x
If you're upgrading from v1.x, note that the API has been simplified for better security:
**Old (v1.x) - INSECURE:**
```typescript
// β Old way - manually setting salt/IV (security risk!)
const config = new AESGCMEncryptionConfigFromEnv(password, salt, iv);
```
**New (v2.x) - SECURE:**
```typescript
// β
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.