# SEAS Encrypt/Decrypt

Encrypt/Decrypt uses the browser's Web Crypto API to create password-encrypted
copies of individual files. It performs no file upload or server-side crypto.
Launch **SEAS Encrypt/Decrypt** from Start, or run `file-crypto` in Terminal.

## Encrypt a file

1. Set Operation to **Encrypt a file**.
2. Select an ordinary file from the **SEAS file** list and click **Use SEAS
   file**, or click **Upload file…** to select a single host file.
3. Enter a strong passphrase and the same value in **Confirm passphrase**.
4. Click **Encrypt**. A new copy appears in `/c/encrypted/locked-1.seasenc`,
   followed by `locked-2.seasenc`, etc., without replacing existing files.
5. Click **Download encrypted file** to retain that copy on the host.

Ordinary VFS text and binary Blob files are supported. `/proc`, devices,
executables, folders and URL-backed media are excluded. A host file is read
directly by the operation; a plaintext copy is not implicitly imported.
Existing VFS plaintext remains available and unchanged after encryption.

Files are limited to **16 MiB of content**. Filenames must be safe basenames
of at most 255 UTF-8 bytes. A passphrase must be nonempty and at most 1,024
UTF-8 bytes. Spaces and Unicode values are significant: no trimming or
Unicode normalization is performed. Unpaired Unicode surrogates are rejected.

## Restore an encrypted file

1. Open a `.seasenc` file in Explorer or use
   `open /c/encrypted/locked-1.seasenc` in Terminal. Alternatively, launch the
   app, select **Decrypt a file**, and click **Import encrypted file…**.
2. Enter the original passphrase and click **Decrypt**.
3. The authenticated file is restored under `/c/decrypted/` with its original
   basename. Existing names are preserved: `notes.txt`, `notes (2).txt`, etc.
4. **Open restored file** uses the normal SEAS file association. Files without
   an associated application stay available in the VFS.

Wrong passphrases and authentication failures show “Unable to decrypt: wrong
passphrase or damaged file.” No output is written. Unsupported versions,
malformed headers and invalid restoration metadata have separate format
errors. The encrypted source is retained after successful restoration.

VFS text files retain their text kind, exact Unicode content and line endings.
Binary bytes and MIME type are preserved. Host files restore as binary data.
Notepad's textarea may display CRLF line endings as LF; simply opening the
restored text does not change its VFS contents.

## Session data and cancellation

Both output directories belong to the temporary session. Reload, simulated
restart and power cycling discard them. Download a container before leaving
the session; later import it and enter its passphrase to restore the file.
There is no password recovery or dependency on a key from the earlier session.

Each window processes one operation at a time in a dedicated module worker.
**Cancel operation**, window closure, Task Manager termination and shutdown
terminate its worker and invalidate pending results. Unmounting/resetting
`/c` invalidates a running operation, even if `/c` is then remounted. A changed
or unavailable destination causes an error rather than a partial write.

Passphrase fields are cleared when an operation starts and after use. The app
does not persist passphrases or keys in browser storage, VFS files, URLs,
process arguments or logs. Download Blob URLs are revoked after use and on
disposal. Worker termination and releasing references are best-effort cleanup;
JavaScript and Web Crypto do not guarantee secure memory erasure.

## Cryptographic profile and trust boundary

Version 1 uses AES-256-GCM, a fresh random 16-byte salt and 12-byte IV per
encryption, and a 128-bit authentication tag. PBKDF2-HMAC-SHA-256 derives a
non-extractable key with 600,000 iterations. Derived keys have only the
operation's required usage and are not cached between operations.

Web Crypto requires a secure context. Localhost/loopback development is
supported; public hosting needs HTTPS. The app explains unavailable Web Crypto
or worker support and disables processing.

Encrypted file contents and original filename/type metadata are protected.
The outer filename, file size, salt, IV and algorithm settings remain visible.
Encryption does not hide plaintext while the application uses it, establish a
sender's identity, or detect replacement with an older valid container.

SEAS's [same-origin iframe isolation finding](security-audit.md) remains open.
Hostile code sharing the desktop's origin can intercept passphrases/plaintext
or use accessible keys. This app does not make the SEAS browser runtime an
isolated vault. Original and restored plaintext files remain available to the
session's apps until removed or reset.

## SEASENC version-1 format

All integers are unsigned and big-endian. A container consists of a **48-byte
public header** followed by ciphertext and its **16-byte GCM tag**. The exact
header bytes are supplied to AES-GCM as `additionalData`.

| Offset | Bytes | Meaning |
| --- | --- | --- |
| 0 | 8 | ASCII `SEASENC` followed by a zero byte |
| 8 | 1 | Container version: `1` |
| 9 | 1 | Cipher profile: `1` = AES-256-GCM |
| 10 | 1 | KDF profile: `1` = PBKDF2-HMAC-SHA-256 |
| 11 | 1 | Authentication tag size in bytes: `16` |
| 12 | 4 | PBKDF2 iterations; readers accept 600,000–1,200,000 inclusive |
| 16 | 16 | Random salt |
| 32 | 12 | Random IV |
| 44 | 4 | Ciphertext-plus-tag byte length, exactly matching the remaining file |

Encryption currently writes 600,000 iterations. Unknown profiles, unsupported
versions, truncated/appended data, sizes and out-of-range derivation costs
reject before key derivation. The accepted upper cost prevents containers
from requesting unbounded derivation work.

The decrypted payload is:

```text
uint32 metadataByteLength
UTF-8 JSON metadata (2–4096 bytes)
original content bytes (0–16 MiB)
```

Metadata has exactly four properties:

```json
{"name":"notes.txt","kind":"text","mimeType":"text/plain","size":123}
```

`kind` is `text` or `binary`. `size` must equal the exact remaining content
length. MIME types are lowercase type/subtype tokens of at most 127 characters,
without parameters. Host MIME types are normalized; absent/invalid types become
`application/octet-stream`. JSON object ordering is not significant because
the entire metadata block is encrypted/authenticated.

Names reject path separators, traversal names, control characters and the
reserved basenames `__proto__`, `constructor` and `prototype`. Restoration
always uses `/c/decrypted/`, with no embedded directory path or executable
node type. UTF-8 decoding is strict and preserves a leading BOM as a character.

Maximum container length is **16,781,380 bytes**:
48-byte header + 4-byte metadata length + 4,096-byte metadata budget +
16,777,216-byte content budget + 16-byte tag. The binary format avoids base64
expansion. Compatibility changes require a new format version and an explicit
reader/migration decision; v1 is not a ZIP, OpenSSL `enc`, or generic encrypted
archive format.

## Implementation and focused checks

- `dist/js/system/file-crypto.js`: profile, format parsing, UTF-8/metadata
  validation, key derivation and AES-GCM operations.
- `dist/js/system/file-crypto-worker.js`: per-operation crypto worker.
- `dist/js/system/crypto-file-io.js`: source snapshots, destination guards and
  validated writes.
- `dist/js/apps/file-crypto.js`: native UI and operation/resource lifecycle.
- `dist/js/filesystem.js`: atomic `importFiles` for text/binary nodes;
  `importBinaryFiles` retains the existing media-upload interface.

Focused helper/VFS checks (Node 20 or later; the new tests install Node's
Web Crypto when running on Node 18):

```sh
node --test test/file-crypto.test.js test/crypto-file-io.test.js test/mounts.test.js
```

With a loopback SEAS server running, use the shared Playwright installation:

```sh
cd ../browser_validation
SEAS_URL=http://127.0.0.1:4173/ node tests/seas-file-crypto.js
```

The helpers cover an independent Node AES-GCM fixture, empty/Unicode/binary
files, salt/IV freshness, wrong passwords, authenticated header/ciphertext/tag
tampering, malformed metadata, limits, staging and destination invalidation.
The Chromium workflow covers VFS/host input, export/reload/import/decrypt,
collision handling, file associations, the 16 MiB limit, cancellation,
unmount/remount, window and Task Manager closure, shutdown/reset and owned
worker/Blob URL cleanup. It rejects external requests and checks that the
workflow makes no upload requests.

The user should check native pickers/downloads, passphrase typing, window
layout and responsiveness in their normal browser: encrypt a small file,
download it, reload SEAS, import/decrypt it, and compare the restored contents.

References: [AES-GCM parameters](https://developer.mozilla.org/en-US/docs/Web/API/AesGcmParams),
[PBKDF2 derivation](https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/deriveKey),
[OWASP PBKDF2 guidance](https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html#pbkdf2),
and [Web Crypto security considerations](https://www.w3.org/TR/webcrypto/#security-considerations).
