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