# Technical documentation — encryptionatrestphp

Evidence date: 2026-10-15. Revision: `main` `9b3df5c` (2025-08-05).

Credential values are omitted. No secrets are committed in this repository.

## What this repository is

A Bitbucket repository containing a small PHP library for AES-256-GCM encryption at rest, plus Markdown documentation, CLI examples, a custom test script, Composer metadata, and a one-page PHP demo form.

There is one branch, `main`. One commit. Eleven tracked files (plus `.gitignore`). Author on the commit: Wessels De Wet (`wessels@overdrive.co.za`). Composer author email is `wessels@silicon.co.za`.

`sonar-project.properties` and `sonarqube_scan.bat` were listed by the onboarding scan and are not in git.

## Repository layout

```text
encryptionatrestphp/
  .gitignore
  README.md                      Library documentation
  PROJECT_SUMMARY.md             Build summary and next steps
  SENSITIVE_DATA_GUIDE.md        Field-type and compliance-oriented guide
  composer.json                  Package encryption-at-rest/php
  index.php                      Browser demo form
  src/
    EncryptionAtRest.php         Sole library class (global namespace)
  examples/
    basic_usage.php
    framework_integration.php
    sensitive_data_examples.php
  tests/
    test_encryption.php          Custom test runner (not PHPUnit)
```

## Languages and runtime

| Piece | Language / tool | Notes |
|---|---|---|
| Library | PHP ≥ 7.4 | Typed properties / typed returns used |
| Crypto | OpenSSL extension | Cipher `aes-256-gcm` |
| Packaging | Composer | Classmap autoload of `src/` |
| Tests | PHP CLI script | `composer test` → `php tests/test_encryption.php` |
| Demo | PHP web SAPI | `index.php` form POST |

No database, cache, queue, message bus, container image, or IaC is present.

## Composer package

| Field | Value |
|---|---|
| `name` | `encryption-at-rest/php` |
| `type` | `library` |
| `license` | `MIT` (no `LICENSE` file in tree) |
| `require` | `php >=7.4`, `ext-openssl` |
| `autoload` | classmap `src/` |
| `autoload-dev` | classmap `tests/` |
| `scripts.test` | `php tests/test_encryption.php` |
| `scripts.example` | `php examples/basic_usage.php` |
| `homepage` / `support` | Placeholder GitHub `yourusername` URLs |

Whether the package is published to Packagist: **Unknown / Requires Confirmation**.

## Core class design

### Type and namespace

- Class name: `EncryptionAtRest` in the **global** namespace (no `namespace` declaration).
- File: `src/EncryptionAtRest.php`.
- Instantiation: `new EncryptionAtRest(?string $key = null)`.

### Constants

| Constant | Value | Role |
|---|---|---|
| `CIPHER` | `aes-256-gcm` | OpenSSL cipher name |
| `KEY_LENGTH` | `32` | AES-256 key size (bytes) |
| `TAG_LENGTH` | `16` | GCM authentication tag (bytes) |
| `IV_LENGTH` | `12` | GCM nonce (bytes) |

### Public methods

| Method | Signature | Behaviour |
|---|---|---|
| Constructor | `__construct(?string $key = null)` | Generate or validate key |
| `encrypt` | `(string $data): string` | Encrypt → base64 |
| `decrypt` | `(string $encryptedData): string` | base64 → decrypt |
| `getKey` | `(): string` | Raw binary key |
| `exportKey` | `(): string` | Base64 key |
| `importKey` | `(string $base64Key): void` | Replace instance key |
| `isSupported` | `static (): bool` | OpenSSL + cipher available |
| `getSupportedCiphers` | `static (): array` | `openssl_get_cipher_methods()` |

Private helpers: `generateKey()`, `validateKey()`.

### Ciphertext encoding (implemented)

```text
plaintext
   │ openssl_encrypt(aes-256-gcm, key, OPENSSL_RAW_DATA, iv, &tag, aad='', tag_len=16)
   ▼
[ 12-byte IV ][ 16-byte tag ][ ciphertext ]
   │ base64_encode
   ▼
string returned to caller
```

Decrypt reverses: strict base64 decode → split → `openssl_decrypt` with tag.

### Exception types

| Condition | Exception |
|---|---|
| Empty encrypt/decrypt input (PHP `empty`) | `InvalidArgumentException` |
| Invalid base64 ciphertext or key | `InvalidArgumentException` |
| Ciphertext too short | `InvalidArgumentException` |
| Key not 32 bytes | `InvalidArgumentException` |
| OpenSSL encrypt/decrypt failure | `Exception` |
| Key generation failure | `Exception` |

## APIs and integrations

- **No HTTP API** exposed by the library.
- **No external SaaS** clients.
- Framework integration is **documentation + example code** only (Laravel service-provider sketch, Symfony service sketch, repository pattern). Consumers must wire DI themselves.
- Environment variable name used in docs/examples: `ENCRYPTION_KEY` (base64 key). Not read automatically by the class.

## Application structure (demo)

`index.php`:

1. `require_once` the class.
2. Renders an HTML form (`method="post"`).
3. On POST, reads `$_POST['text']`, constructs a **new** encryptor (new random key), encrypts, decrypts, prints match.

There is no session storage of the key. XSS/CSRF protections are not implemented — treat as local demo only.

## Storage

None in-repo. Callers store:

- Ciphertext: typically DB columns or files (examples).
- Keys: env vars / KMS (documented guidance).

File encrypt helpers in `examples/framework_integration.php` (`FileEncryption`) read/write local paths; they are example classes, not library API.

## Background workers / queues / monitoring

None.

## Security notes (from code + docs)

**Implemented:**

- Authenticated encryption (GCM tag).
- Random IV per encryption.
- Random key generation via `random_bytes`.
- Strict base64 decode for ciphertext and imported keys.

**Documented (caller must do):**

- Keep keys out of git.
- Separate keys per environment.
- Rotate keys.
- Do not log secrets.
- Prefer hashing for authentication passwords (`password_hash` in guide examples).

**Caveats observed:**

- `getKey()` returns raw key material to any holder of the object — no access control.
- `empty()` rejects string `"0"`.
- README “chunk” performance claim is not reflected in code (single-shot OpenSSL).
- Compliance badges in `SENSITIVE_DATA_GUIDE.md` are not third-party audit artefacts.

## Development and testing

### Local usage

```bash
# From repo root
php examples/basic_usage.php
php examples/framework_integration.php
php examples/sensitive_data_examples.php
php tests/test_encryption.php
# or
composer test
composer example
```

Optional: serve `index.php` with any PHP built-in or web server for the form demo.

### Test suite contents (`EncryptionTest`)

| Test method | What it checks |
|---|---|
| `testEncryptionSupport` | `isSupported()` |
| `testBasicEncryption` | Round-trip string |
| `testKeyManagement` | export/import decrypt |
| `testErrorHandling` | empty, invalid base64, short payload |
| `testLargeData` | ~1MB string + timings |
| `testSpecialCharacters` | Large Unicode sample |
| `testJsonData` | JSON encode round-trip |
| `testBinaryData` | 1024 random bytes |

No PHPUnit XML, no CI job, no coverage report in git. `PROJECT_SUMMARY.md` asserts all tests pass; this Silicon Ark onboarding did not re-run them on the agent host.

### `.gitignore`

Generic Bitbucket template (node, Java, Python, IDE, OS junk). It does **not** list `.env`, `vendor/`, or PHP-specific artefacts. Whether that is intentional: **Unknown / Requires Confirmation**.

## Infrastructure and deployment

| Area | Status |
|---|---|
| Docker / Compose | Not present |
| Bitbucket Pipelines | Not present |
| SonarQube project files | Not in git (scan host may have had local copies) |
| Hosting / URL | N/A (library) |
| Environments | Documented advice only |

## Installation paths (documented)

1. **Copy file:** place `src/EncryptionAtRest.php` and `require_once`.
2. **Composer:** classmap autoload when the package is available as a dependency; publish status unclear.

## Known implementation / documentation issues

1. Placeholder GitHub URLs in `composer.json` vs Bitbucket remote.
2. Missing `LICENSE` file despite MIT declaration.
3. Broken retrieve path in `UserRepository::getUser` example.
4. Scan-listed Sonar/batch files absent from git.
5. README chunked-processing claim vs single-buffer OpenSSL calls.

## Related documents in Silicon Ark

- `project-plan.md`
- `prd.md`
- `features.md`
- `business-rules.md`
