> ## Documentation Index
> Fetch the complete documentation index at: https://docs-terra.withunify.org/llms.txt
> Use this file to discover all available pages before exploring further.

# Encryption & PII

> How Terra protects sensitive personal information with encryption

# Encryption & PII

> Sensitive data is encrypted at rest using AES-256-GCM.

## What's Encrypted

| Data                 | Table                                  | Method      |
| -------------------- | -------------------------------------- | ----------- |
| Bank account numbers | `applicant_bank_accounts`              | AES-256-GCM |
| SSNs                 | `applicant_pii`                        | AES-256-GCM |
| Plaid access tokens  | `form_submissions.plaid_access_tokens` | AES-256-GCM |
| OAuth tokens         | `airtable_connections`                 | AES-256-GCM |

## Encryption Implementation

```typescript theme={null}
// src/lib/encryption.ts

import { createCipheriv, createDecipheriv, randomBytes } from "crypto";

const ALGORITHM = "aes-256-gcm";
const KEY = Buffer.from(process.env.ENCRYPTION_KEY!, "hex");

export function encrypt(plaintext: string): string {
  const iv = randomBytes(16);
  const cipher = createCipheriv(ALGORITHM, KEY, iv);

  let encrypted = cipher.update(plaintext, "utf8", "hex");
  encrypted += cipher.final("hex");

  const authTag = cipher.getAuthTag();

  // Format: iv:authTag:ciphertext
  return `${iv.toString("hex")}:${authTag.toString("hex")}:${encrypted}`;
}

export function decrypt(encrypted: string): string {
  const [ivHex, authTagHex, ciphertext] = encrypted.split(":");

  const iv = Buffer.from(ivHex, "hex");
  const authTag = Buffer.from(authTagHex, "hex");

  const decipher = createDecipheriv(ALGORITHM, KEY, iv);
  decipher.setAuthTag(authTag);

  let decrypted = decipher.update(ciphertext, "hex", "utf8");
  decrypted += decipher.final("utf8");

  return decrypted;
}
```

## Masking for Display

When showing encrypted data in the UI, we display masks:

```typescript theme={null}
// Show last 4 digits only
function maskAccountNumber(encrypted: string): string {
  const decrypted = decrypt(encrypted);
  return `****${decrypted.slice(-4)}`;
}
```

## Key Management

* Encryption key stored in Doppler as `ENCRYPTION_KEY`
* 256-bit key (64 hex characters)
* Key rotation requires re-encrypting existing data

***

<CardGroup cols={2}>
  <Card title="File Storage" icon="folder" href="/core-systems/data/file-storage">
    Secure file handling
  </Card>

  <Card title="Security" icon="shield" href="/operations/security">
    Full security guide
  </Card>
</CardGroup>
