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