vitaminc-encrypt 0.1.0-pre4

Secure, flexible and fast encryption for Rust types. Part of the Vitamin-C cryptographic suite.
Documentation
# Vitamin C Encrypt

[![Crates.io](https://img.shields.io/crates/v/vitaminc-encrypt.svg)](https://crates.io/crates/vitaminc-encrypt)
[![Workflow Status](https://github.com/cipherstash/vitaminc/actions/workflows/test.yml/badge.svg)](https://github.com/cipherstash/vitaminc/actions/workflows/test.yml)

Secure, flexible and fast encryption for Rust types.

This crate is part of the [Vitamin C](https://github.com/cipherstash/vitaminc) framework to make cryptography code healthy.

## Features

- **Type-safe encryption**: Encrypt and decrypt Rust types with compile-time safety
- **AES-256-GCM**: Uses AES-256-GCM authenticated encryption via AWS-LC
- **256-bit keys only**: Enforces quantum-resistant key sizes for future security
- **Protected types integration**: Works seamlessly with `vitaminc-protected` for sensitive data handling
- **Additional Authenticated Data (AAD)**: Support for authenticated but unencrypted data
- **Automatic nonce generation**: Secure random nonce generation for each encryption operation

## Installation

Add this to your `Cargo.toml`:

```toml
[dependencies]
vitaminc-encrypt = "0.1.0-pre4"
vitaminc-random = "0.1.0-pre4"  # For key generation
```

## Quick Start

```rust
use vitaminc_encrypt::Key;
use vitaminc_random::{SafeRand, SeedableRng, Generatable};

// Generate a key
let mut rng = SafeRand::from_entropy();
let key = Key::random(&mut rng).expect("Failed to generate key");

// Encrypt a message
let ciphertext = vitaminc_encrypt::encrypt(&key, "secret message").expect("Failed to encrypt");

// Decrypt it back
let plaintext: String = vitaminc_encrypt::decrypt(&key, ciphertext).expect("Failed to decrypt");
assert_eq!(plaintext, "secret message");
```

## Usage

### Key Management

The [`Key`] type represents a 256-bit encryption key. Vitamin C only supports 256-bit keys to ensure quantum security and compatibility with AWS-LC.

#### Generating a Key

```rust
use vitaminc_encrypt::Key;
use vitaminc_random::{SafeRand, SeedableRng, Generatable};

let mut rng = SafeRand::from_entropy();
let key = Key::random(&mut rng).expect("Failed to generate key");
```

#### Creating a Key from Bytes

```rust
use vitaminc_encrypt::Key;

let key_bytes = [0u8; 32];  // In practice, use securely generated bytes
let key = Key::from(key_bytes);
```

### Encrypting Data

The [`encrypt`] function can encrypt any type that implements the [`Encrypt`] trait. Built-in support includes:

- `String`
- `&str`
- `Vec<u8>`
- `[u8; N]` (fixed-size byte arrays)
- `Protected<T>` where `T` implements `Encrypt`

```rust
use vitaminc_encrypt::{encrypt, Key};
use vitaminc_random::{SafeRand, SeedableRng, Generatable};

let key = Key::random(&mut SafeRand::from_entropy()).expect("Failed to generate key");

// Encrypt a string
let ciphertext = encrypt(&key, "secret message").expect("encryption failed");

// Encrypt bytes
let data = vec![1, 2, 3, 4, 5];
let ciphertext = encrypt(&key, data).expect("encryption failed");

// Encrypt a fixed-size array
let array = [0u8; 32];
let ciphertext = encrypt(&key, array).expect("encryption failed");
```

### Decrypting Data

The [`decrypt`] function requires you to specify the expected type:

```rust
# use vitaminc_encrypt::{encrypt, decrypt, Key, LocalCipherText};
# use vitaminc_random::{SafeRand, SeedableRng, Generatable};
# let key = Key::random(&mut SafeRand::from_entropy()).expect("Failed to generate key");

// Decrypt to String
let ciphertext = encrypt(&key, "secret message").expect("encryption failed");
let plaintext: String = decrypt(&key, ciphertext).expect("decryption failed");

// Decrypt to Vec<u8>
let ciphertext = encrypt(&key, vec![1, 2, 3, 4, 5]).expect("encryption failed");
let bytes: Vec<u8> = decrypt(&key, ciphertext).expect("decryption failed");

// Decrypt to fixed-size array
let ciphertext = encrypt(&key, [0u8; 32]).expect("encryption failed");
let array: [u8; 32] = decrypt(&key, ciphertext).expect("decryption failed");
```

### Additional Authenticated Data (AAD)

AAD allows you to authenticate additional context alongside the ciphertext without encrypting it. This is useful for binding metadata to encrypted data.

```rust
use vitaminc_encrypt::{encrypt_with_aad, decrypt_with_aad, Key};

let key = Key::from([0u8; 32]);

// Encrypt with context
let user_id = "user_123";
let ciphertext = encrypt_with_aad(&key, "secret message", user_id).expect("encryption failed");

// Decrypt with the same context
let plaintext: String = decrypt_with_aad(&key, ciphertext, user_id).expect("decryption failed");
assert_eq!(plaintext, "secret message");
```

#### AAD Must Match

Decryption will fail if the AAD doesn't match:

```rust
# use vitaminc_random::{SafeRand, SeedableRng, Generatable};
# use vitaminc_encrypt::Key;
# let key = Key::random(&mut SafeRand::from_entropy()).expect("Failed to generate key");
use vitaminc_encrypt::{encrypt_with_aad, decrypt_with_aad};

// Encrypt with one context
let ciphertext = encrypt_with_aad(&key, "secret", "context_1").expect("encryption failed");

// Try to decrypt with different context - this will fail!
let result: Result<String, _> = decrypt_with_aad(&key, ciphertext, "context_2");
assert!(result.is_err());
```

### Working with Protected Types

Vitamin C Encrypt integrates with `vitaminc-protected` to ensure sensitive data is handled securely:

```rust
use vitaminc_protected::Protected;
use vitaminc_encrypt::{encrypt, decrypt, Key};
use vitaminc_random::{SafeRand, SeedableRng, Generatable};

let key = Key::random(&mut SafeRand::from_entropy()).expect("Failed to generate key");

// Encrypt protected data
let sensitive = Protected::new("password123".to_string());
let ciphertext = encrypt(&key, sensitive).expect("encryption failed");

// Decrypt back to protected data
let decrypted: Protected<String> = decrypt(&key, ciphertext).expect("decryption failed");
```

### Encrypting Keys (Key Wrapping)

Keys can be encrypted with other keys, enabling key hierarchy and key wrapping:

```rust
use vitaminc_encrypt::{Key, encrypt, decrypt};
use vitaminc_random::{SafeRand, SeedableRng, Generatable};

let mut rng = SafeRand::from_entropy();

// Generate a key encryption key (KEK)
let kek = Key::random(&mut rng).expect("key generation failed");

// Generate a data encryption key (DEK)
let dek = Key::random(&mut rng).expect("key generation failed");

// Wrap the DEK with the KEK
let wrapped_dek = encrypt(&kek, dek).expect("encryption failed");

// Later, unwrap the DEK
let unwrapped_dek: Key = decrypt(&kek, wrapped_dek).expect("decryption failed");
```

### Convenience Functions vs Traits

This crate provides both convenience functions and traits:

**Convenience functions** (recommended for most use cases):
- [`encrypt`] - Encrypt with no AAD
- [`encrypt_with_aad`] - Encrypt with AAD
- [`decrypt`] - Decrypt with no AAD
- [`decrypt_with_aad`] - Decrypt with AAD

**Traits** (for custom implementations):
- [`Encrypt`] - Implement to make your types encryptable
- [`Decrypt`] - Implement to make your types decryptable
- [`Cipher`] - Implement to create custom cipher algorithms

Example using traits directly:

```rust
use vitaminc_encrypt::{Encrypt, Decrypt, Aes256Cipher, Key};

let key = Key::from([0u8; 32]);
let cipher = Aes256Cipher::new(&key).expect("cipher creation failed");

let ciphertext = "secret".encrypt(&cipher).expect("encryption failed");
let plaintext: String = String::decrypt(ciphertext, &cipher).expect("decryption failed");
```

### Custom Encryptable Types

You can implement [`Encrypt`] and [`Decrypt`] for your own types to enable selective field encryption:

```rust
use vitaminc_encrypt::{Encrypt, Decrypt, Cipher, IntoAad, Unspecified, LocalCipherText};

struct User {
    id: u64,
    email: String,
    ssn: String,
}

struct EncryptedUser {
    id: u64,
    email: String,
    ssn: LocalCipherText,  // Only encrypt the SSN
}

impl Encrypt for User {
    type Encrypted = EncryptedUser;

    fn encrypt_with_aad<'a, C, A>(
        self,
        cipher: &C,
        aad: A,
    ) -> Result<Self::Encrypted, Unspecified>
    where
        C: Cipher,
        A: IntoAad<'a>,
    {
        Ok(EncryptedUser {
            id: self.id,
            email: self.email,
            ssn: self.ssn.encrypt_with_aad(cipher, aad).expect("encryption failed"),
        })
    }
}

impl Decrypt for User {
    type Encrypted = EncryptedUser;

    fn decrypt_with_aad<'a, C, A>(
        encrypted: Self::Encrypted,
        cipher: &C,
        aad: A,
    ) -> Result<Self, Unspecified>
    where
        C: Cipher,
        A: IntoAad<'a>,
    {
        Ok(User {
            id: encrypted.id,
            email: encrypted.email,
            ssn: String::decrypt_with_aad(encrypted.ssn, cipher, aad).expect("decryption failed"),
        })
    }
}
```

## Security Features

### AES-256-GCM

This crate uses AES-256-GCM (Galois/Counter Mode) which provides:

- **Confidentiality**: Data is encrypted with AES-256
- **Authenticity**: Built-in authentication prevents tampering
- **Performance**: Hardware-accelerated on most modern CPUs

### AWS-LC

Encryption is powered by [AWS-LC](https://github.com/aws/aws-lc-rs), a FIPS-validated cryptographic library maintained by Amazon Web Services.

### 256-bit Keys Only

Vitamin C enforces 256-bit keys to ensure:

- Resistance to quantum computer attacks (via AES-256)
- Compatibility with AWS-LC's recommended parameters
- No risk of accidentally using weaker key sizes

### Automatic Nonce Generation

Each encryption operation generates a unique random nonce, preventing nonce reuse which could compromise security.

### Unspecified Errors

Encryption and decryption operations return an [`Unspecified`] error type that reveals no information about failures. This prevents side-channel attacks that could leak information through error messages.

## Best Practices

1. **Generate keys securely**: Always use `Key::random()` with a cryptographically secure RNG
2. **Protect keys in memory**: The `Key` type uses `Protected` internally to zeroize keys when dropped
3. **Use AAD for context**: Include relevant context (user ID, record ID, etc.) as AAD to prevent ciphertext substitution
4. **Never reuse keys across environments**: Use different keys for development, staging, and production
5. **Rotate keys regularly**: Implement key rotation policies for long-lived systems
6. **Store keys securely**: Use key management systems (KMS) for production deployments

## Performance

Vitamin C Encrypt is designed for both security and performance:

- **Zero-copy operations** where possible
- **Hardware acceleration** via AWS-LC's AES-NI support
- **Minimal allocations** during encryption/decryption

## Error Handling

All encryption operations return `Result<T, Unspecified>` where [`Unspecified`] is an opaque error type that reveals no details about the failure. This is intentional to prevent side-channel attacks.

```rust
use vitaminc_encrypt::{Key, encrypt, Unspecified};
use vitaminc_random::{SafeRand, SeedableRng, Generatable};

let key = Key::random(&mut SafeRand::from_entropy()).expect("Failed to generate key");

match encrypt(&key, "message") {
    Ok(ciphertext) => println!("Encrypted successfully"),
    Err(Unspecified) => eprintln!("Encryption failed"),
}
```

## CipherStash

Vitamin C is brought to you by the team at [CipherStash](https://cipherstash.com).

License: MIT