.afterme Open Container Format

Specification v1.0 · AES-256-GCM · PBKDF2 · Open format

Overview

The .afterme file format is an open, documented container format designed for long-term archival and secure storage of sensitive personal documents. It prioritizes user ownership, platform independence, and future-proof access. Even if the After Me application or company ceases to exist, users with the correct credentials can always access their data using standard open-source tools.

This specification is public and stable. Any changes to the format will be versioned and documented.

File Structure

An .afterme file is a standard ZIP archive containing:

.afterme (ZIP Archive)
├── README.txt           # Human-readable instructions for manual recovery
├── manifest.json        # Metadata about the vault contents (unencrypted)
├── vault.enc            # The core encrypted data payload (AES-256-GCM)
└── key.enc              # Content encryption key, wrapped with access credential

manifest.json

Non-sensitive metadata. Schema:

{
  "version": "1.0",
  "created_at": "2023-10-27T10:00:00Z",
  "vault_id": "uuid-string",
  "owner_name": "John Doe",
  "document_count": 15,
  "categories": ["Identity", "Finance", "Legal"],
  "encryption_algo": "AES-256-GCM",
  "kdf_algo": "PBKDF2-HMAC-SHA256"
}

Privacy Note

The owner_name field is stored unencrypted intentionally. It exists so that survivors who receive an .afterme file can identify whose vault it is before attempting decryption. This is important for scenarios where a family member may possess multiple .afterme files from different relatives.

The owner_name field is optional. If the user omits it, the field should be absent from the JSON or set to null. Implementations must not require this field to be present.

vault.enc

Encrypted payload. Algorithm: AES-256-GCM. Key: 32 bytes. Nonce/IV: 12 bytes. Auth tag: 16 bytes.

Wire format (byte-level layout):

[IV (12 bytes)][Auth Tag (16 bytes)][Ciphertext]
OffsetLengthField
012IV (nonce)
1216GCM authentication tag
28variableCiphertext (encrypted JSON payload)
Note: The authentication tag appears before the ciphertext. This differs from many library conventions where the tag is appended after the ciphertext. See Implementation Notes for guidance.

key.enc

Content Encryption Key (CEK) wrapped with the user's access credential (e.g., QR code key). Wrapping: AES-256-GCM. Key derivation: PBKDF2-HMAC-SHA256 with 600,000 iterations, 32-byte salt.

Binary format (byte-level layout):

[Salt (32 bytes)][IV (12 bytes)][Auth Tag (16 bytes)][Encrypted CEK (32 bytes)]
OffsetLengthField
032PBKDF2 salt
3212IV (nonce) for AES-256-GCM key wrap
4416GCM authentication tag
6032Encrypted Content Encryption Key

Total file size: 92 bytes (fixed).

Note: As with vault.enc, the authentication tag precedes the ciphertext (the encrypted CEK). See Implementation Notes for library-specific guidance.

QR Code Access Key

The Access Key is the secret credential used to derive the Key Encryption Key (KEK) via PBKDF2. It is delivered to the user as a QR code.

Encryption Details

KDF: PBKDF2, HMAC-SHA256, 600,000 iterations, 32-byte random salt.

Content Encryption: AES-256-GCM, 32-byte key, 12-byte nonce, 16-byte tag.

Recovery Process

  1. Unzip the .afterme file.
  2. Read README.txt for instructions.
  3. Locate the decoder tool or write one based on this spec.
  4. Provide the QR code string (Access Key).
  5. Decoder reads the salt (first 32 bytes) from key.enc.
  6. Decoder derives KEK from Access Key via PBKDF2-HMAC-SHA256 (600,000 iterations).
  7. Decoder reads IV, Auth Tag, and Encrypted CEK from key.enc; decrypts to obtain CEK.
  8. Decoder reads IV and Auth Tag from the start of vault.enc; decrypts remaining ciphertext using CEK.
  9. Parses the resulting JSON and extracts the documents.

Implementation Notes

Tag-Before-Ciphertext Convention

The .afterme v1.0 wire format places the GCM authentication tag before the ciphertext in both vault.enc and key.enc. This is a deliberate design choice baked into the reference implementation and all existing encrypted files.

Many cryptographic libraries expect the tag appended after the ciphertext (e.g., Python's cryptography AESGCM, Go's crypto/cipher, WebCrypto). When working with such libraries, implementors must rearrange the bytes:

Reading (decryption)

  1. Parse the wire format: [IV][Tag][Ciphertext]
  2. Rearrange for the library: pass [Ciphertext][Tag] (concatenated) as the "ciphertext" input, with the IV/nonce separately.

Writing (encryption)

  1. The library returns [Ciphertext][Tag] (concatenated) or separate values.
  2. Rearrange to the wire format: write [IV][Tag][Ciphertext] to the file.

Example: Python (cryptography library)

# Decrypting vault.enc:
data = open("vault.enc", "rb").read()
iv = data[:12]
tag = data[12:28]
ciphertext = data[28:]
# AESGCM.decrypt() expects ciphertext+tag appended:
plaintext = AESGCM(cek).decrypt(iv, ciphertext + tag, None)

# Decrypting key.enc:
data = open("key.enc", "rb").read()
salt = data[:32]
iv = data[32:44]
tag = data[44:60]
encrypted_cek = data[60:92]
cek = AESGCM(kek).decrypt(iv, encrypted_cek + tag, None)

Example: Node.js (crypto module)

// Decrypting vault.enc:
const data = fs.readFileSync('vault.enc');
const iv = data.subarray(0, 12);
const tag = data.subarray(12, 28);
const ciphertext = data.subarray(28);
const decipher = crypto.createDecipheriv('aes-256-gcm', cek, iv);
decipher.setAuthTag(tag);
const plaintext = Buffer.concat([
  decipher.update(ciphertext), decipher.final()
]);
Note: Node.js crypto.createDecipheriv for GCM accepts the tag separately via setAuthTag(), so no rearrangement is needed — simply slice the tag and ciphertext from the wire format and pass them independently.

Open-Source Decoder

We publish a reference decoder so your family can open your vault without our app. Download from our GitHub repository or implement your own using this specification.

Download Open-Source Decoder →

Decoder repository: github.com/afterme/decoder

Future Compatibility

Last updated: March 2026. This specification is maintained at https://afterme.app/format-spec