keycrypt 0.1.0

AES-256-GCM encryption helpers backed by the OS keychain (auto-init key on encrypt, strict decrypt, Zeroize in-memory keys).
Documentation
# Security Policy (keycrypt)

## Overview

`keycrypt` provides symmetric encryption using **AES-256-GCM**.

A single **32-byte master key** is generated once and stored in the OS credential store via
the [`keyring`](https://crates.io/crates/keyring) crate. Encryption and decryption operations
use this key and are authenticated (tamper-detecting) via GCM.

This crate is designed for application-level encryption where storing a key in the OS keychain
is acceptable and convenient.

---

## Ciphertext Format

Current format:

- `v1:nonce_b64:ciphertext_b64`

Legacy format supported for backward compatibility:

- `nonce_b64:ciphertext_b64`

### Encoding details

- **Nonce**: 12 bytes (AES-GCM standard), encoded using URL-safe Base64 (no padding)
- **Ciphertext**: includes the GCM authentication tag (AES-GCM appends it automatically)

---

## Associated Authenticated Data (AAD)

All encryption/decryption operations bind to a fixed AAD:

- `keycrypt:crypto:v1`

AAD provides **domain separation / protocol binding**, meaning ciphertext produced by this crate
is not trivially reusable in other contexts that use different AAD values.

---

## Key Storage by OS

Key storage depends on the operating system backend used by `keyring`:

- **macOS**: Apple Keychain (`apple-native`)
- **Windows**: Windows Credential Manager (`windows-native`)
- **Linux (default)**: native Linux keyring (`linux-native`)
- **Linux (optional)**: persistent dual-store using keyutils + Secret Service
  (`linux-persistent` feature)

---

## macOS Keychain Prompts

On macOS, accessing Keychain entries may trigger system permission prompts depending on:

- user/system security policy
- keychain access control settings
- app codesigning / sandboxing configuration

This is expected OS behavior and not controlled by this crate.

---

## Key Rotation and Backward Compatibility

Changing any of the following can make previously encrypted values undecryptable:

- keychain identifiers (`KEYCHAIN_SERVICE` / `KEYCHAIN_ACCOUNT`)
- the fixed AAD value
- the ciphertext format versioning rules

### Recommended rotation approach

1. Introduce a new key identifier (example: `crypto_key_v2`) while keeping the old key.
2. Encrypt new data using v2.
3. During decrypt, attempt v2 first, then fall back to v1.
4. After a migration window, retire the old key and remove v1 fallback support.

---

## Threat Model Notes

- AES-256-GCM provides **confidentiality + integrity** (tamper detection).
- Authentication failures return a generic error to reduce oracle-style information leakage.
- Keys loaded into memory are wrapped in `Zeroizing<[u8; 32]>` to reduce linger time.
  This is **best-effort** and does not guarantee protection against advanced memory attacks.

---

## Reporting Security Issues

If you discover a security issue, please report it privately by opening a GitHub Security Advisory
or contacting the maintainer directly.

Do not open public issues for vulnerabilities.