# @vvlad1973/crypto

A TypeScript library for encrypting and decrypting text using AES-256-CTR encryption with PBKDF2 key derivation.

This library uses Node.js native `crypto` module for secure encryption operations.

## Features

- AES-256-CTR encryption for reversible data (e.g. PII)
- One-way password hashing with `scrypt` (OWASP-recommended, memory-hard)
- PBKDF2 key derivation with configurable parameters
- Support for both number and Buffer initialization vectors
- TypeScript support with full type definitions
- Dual API: constructor with options object or separate parameters
- UUID v4 generation utility
- Zero external dependencies (uses native Node.js crypto)

## Installation

```bash
npm install @vvlad1973/crypto
```

## Usage

### Importing

```typescript
import Crypto, { CryptoOptions, isCrypto } from '@vvlad1973/crypto';
```

### Basic Usage

```typescript
import Crypto from '@vvlad1973/crypto';

const password = 'your-password';
const salt = 'your-salt';

// Create an instance using separate parameters
const crypto = new Crypto(password, salt);

// Encrypt a text
const plainText = 'Hello, World!';
const encryptedText = crypto.encrypt(plainText);
console.log('Encrypted:', encryptedText);

// Decrypt the text
const decryptedText = crypto.decrypt(encryptedText);
console.log('Decrypted:', decryptedText);
```

### Using Options Object

```typescript
import Crypto, { CryptoOptions } from '@vvlad1973/crypto';

const options: CryptoOptions = {
  password: 'your-password',
  salt: 'your-salt',
  algorithm: 'SHA512',
  iterations: 1000,
  keyLength: 32,
  iv: 5
};

const crypto = new Crypto(options);
const encrypted = crypto.encrypt('Secret message');
const decrypted = crypto.decrypt(encrypted);
```

### Using Buffer IV

```typescript
import Crypto from '@vvlad1973/crypto';
import { randomBytes } from 'crypto';

// Generate a random 16-byte initialization vector
const ivBuffer = randomBytes(16);

const crypto = new Crypto({
  password: 'your-password',
  salt: 'your-salt',
  iv: ivBuffer
});

const encrypted = crypto.encrypt('Secret message');
```

### Generating UUIDs

```typescript
import Crypto from '@vvlad1973/crypto';

// Generate a UUID v4
const uuid = Crypto.getUUID();
console.log(uuid); // e.g., '9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d'
```

### Type Guard

```typescript
import Crypto, { isCrypto } from '@vvlad1973/crypto';

const crypto = new Crypto('password', 'salt');

if (isCrypto(crypto)) {
  // TypeScript knows crypto has encrypt/decrypt methods
  const encrypted = crypto.encrypt('text');
}
```

### Password Hashing

The `Crypto` class encrypts **recoverable** data. For passwords, which must never be
recoverable, use the standalone `hashPassword` / `verifyPassword` functions. They are
built on Node.js native `scrypt` (a memory-hard, OWASP-recommended KDF), generate a
fresh per-record salt on every call, and compare in constant time.

```typescript
import { hashPassword, verifyPassword } from '@vvlad1973/crypto';

// On registration / password change — store the returned string as-is:
const stored = await hashPassword('correct horse battery staple');
// e.g. 'scrypt$1$N=131072,r=8,p=1$<saltHex>$<hashHex>'

// On login:
const ok = await verifyPassword('correct horse battery staple', stored); // true
const no = await verifyPassword('wrong password', stored);               // false
```

The stored value is a single self-describing string that carries the algorithm, a
format version, the scrypt parameters and the salt — so the cost profile can change
over time without any storage migration, and the value is distinguishable from other
schemes (legacy `bcrypt` `$2a$…`, a future `argon2id$…`, etc.).

To trade strength for speed (for example in a test suite), lower the cost parameters:

```typescript
const cheap = await hashPassword('pw', { params: { N: 16384 } });
```

> The reversible `encrypt`/`decrypt` cipher and the `hashPassword`/`verifyPassword`
> functions are **not** interchangeable: use the cipher for data you must read back,
> and the password functions for secrets that must stay one-way.

## API

### Constructor

#### Using separate parameters

```typescript
new Crypto(
  password: string,
  salt: string,
  algorithm?: string,
  iterations?: number,
  keyLength?: number,
  iv?: number | Buffer
)
```

#### Using options object

```typescript
new Crypto(options: CryptoOptions)
```

**CryptoOptions interface:**

```typescript
interface CryptoOptions {
  password: string;      // Password for key derivation
  salt: string;          // Salt for key derivation
  algorithm?: string;    // Hash algorithm (default: 'SHA512')
  iterations?: number;   // PBKDF2 iterations (default: 1000)
  keyLength?: number;    // Key length in bytes (default: 32)
  iv?: number | Buffer;  // Initialization vector (default: random 16 bytes)
}
```

**Parameters:**

- `password` - The password used for PBKDF2 key derivation
- `salt` - The salt used for PBKDF2 key derivation
- `algorithm` - Hash algorithm for PBKDF2 (default: `'SHA512'`)
- `iterations` - Number of PBKDF2 iterations (default: `1000`)
- `keyLength` - Derived key length in bytes (default: `32` for AES-256)
- `iv` - Initialization vector: either a number (converted to 16-byte Buffer) or a Buffer directly (default: random 16 bytes)

### Instance Methods

#### encrypt(text: string): string

Encrypts the given text using AES-256-CTR encryption.

- `text` - The plain text to encrypt
- **Returns:** The encrypted text as a hexadecimal string

#### decrypt(text: string): string

Decrypts the given encrypted text using AES-256-CTR decryption.

- `text` - The encrypted text as a hexadecimal string
- **Returns:** The decrypted plain text

### Static Methods

#### Crypto.getUUID(): string

Generates a random UUID v4 string using Node.js native crypto.

- **Returns:** A UUID v4 string (e.g., `'9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d'`)

### Utility Functions

#### isCrypto(object: any): object is Crypto

Type guard function to check if an object is an instance of Crypto.

- `object` - The object to check
- **Returns:** `true` if the object is a Crypto instance, `false` otherwise

### Password Functions

#### hashPassword(plain: string, options?: HashPasswordOptions): Promise&lt;string&gt;

Hashes a plaintext password with `scrypt` for storage. A fresh 16-byte salt is
generated per call.

- `plain` - The plaintext password to hash
- `options.params` - Optional scrypt parameter overrides (`N`, `r`, `p`, `keyLength`);
  omitted fields fall back to `DEFAULT_SCRYPT_PARAMS`
- **Returns:** The self-describing stored hash `scrypt$1$<params>$<saltHex>$<hashHex>`

#### verifyPassword(plain: string, stored: string): Promise&lt;boolean&gt;

Verifies a candidate password against a value produced by `hashPassword`, comparing in
constant time. A structurally invalid or non-scrypt `stored` value yields `false`
rather than throwing.

- `plain` - The candidate plaintext password
- `stored` - The stored hash string
- **Returns:** `true` when the password matches, `false` otherwise

#### DEFAULT_SCRYPT_PARAMS

The default OWASP scrypt profile: `{ N: 131072, r: 8, p: 1, keyLength: 32 }`
(about 128 MiB and 100-250 ms per hash on a modern CPU).

## Testing

This library uses Vitest for testing with comprehensive coverage requirements.

### Run all tests

```bash
npm test
```

### Run tests in watch mode

```bash
npm run test:watch
```

### Run tests with UI

```bash
npm run test:ui
```

### Generate coverage report

```bash
npm run test:coverage
```

### Coverage Requirements

- Lines: 90%
- Functions: 85%
- Branches: 90%
- Statements: 90%

Current coverage: **100%** across all metrics

## Building

To build the TypeScript project:

```bash
npm run build
```

This will compile TypeScript files to the `dist` directory with type definitions.

## Documentation

To generate TypeDoc documentation:

```bash
npm run doc
```

Documentation will be generated in the `docs` directory.

## License

This project is licensed under the MIT License with Commercial Use - see the LICENSE file for details.

## Author

Vladislav Vnukovskiy <vvlad1973@gmail.com>
