Skip to content

A library and CLI tool providing easy-to-use encryption capabilities for Node.js and browser environments.

License

Notifications You must be signed in to change notification settings

PiperLiu/easy-cipher-mate

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

31 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

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

npm install easy-cipher-mate

With yarn

yarn add easy-cipher-mate

πŸ–₯️ CLI Usage

Encrypt a file

easy-cipher-mate encrypt-file -i input.txt -o output.txt -p yourpassword -a aes-gcm

Decrypt a file

easy-cipher-mate decrypt-file -i encrypted.txt -o decrypted.txt -p yourpassword -a aes-gcm

Encrypt a text file line by line

easy-cipher-mate encrypt-text-file -f input.txt -p yourpassword -a aes-gcm -e utf-8

Decrypt a text file line by line

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

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

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

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

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

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

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

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

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

class AESGCMEncryptionConfig {
  constructor(password: string, textEncoding?: TextEncoding)
}

ChaCha20Poly1305EncryptionConfig

class ChaCha20Poly1305EncryptionConfig {
  constructor(password: string, textEncoding?: TextEncoding)
}

EncryptionService

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>
}

πŸ“ 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.

πŸ“„ License

MIT License. See 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:

// ❌ 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.

About

A library and CLI tool providing easy-to-use encryption capabilities for Node.js and browser environments.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published