Encryption Model

How SikkerKey protects your secrets, credentials, and data.

Every secret in SikkerKey is encrypted with three independent layers. Passwords are hashed, sessions are protected, and nothing sensitive is stored in plaintext.

Three Layers of Secret Encryption

Each secret is wrapped in three layers of AES-256 encryption:

  1. Your secret is encrypted with its own unique data key. Every secret gets a fresh key, so each encrypted value is independent of every other.

  2. The data key is encrypted with your project's master key. Each project has its own independently generated master key, so each project is cryptographically separate from the rest.

  3. The project master key is itself encrypted under a root key. SikkerKey holds the root key on separate, isolated infrastructure; to read a secret, the wrapped master key is sent there and only that one project's key comes back, for the lifetime of the request. The root key never reaches the infrastructure that stores your data.

To read a single secret, all three layers are unwrapped in sequence. At every level, the database holds only encrypted material.

What each layer protects

  • Each secret is independent. Every secret has its own data key, so one encrypted value is unrelated to any other.
  • Each project is independent. Every project has its own master key, so projects are cryptographically separate.
  • Values are bound to their secret. An encrypted value carries the identity of the secret it belongs to, so it cannot be moved to another secret and still decrypt.
  • Everything at rest is ciphertext. At every layer, the database holds only encrypted material.

Key lifecycle

Key material is held in memory only for the duration of a single operation. Once encryption or decryption completes, the keys are cleared from memory before the response is sent.

Password Security

Account passwords are hashed with Argon2id, a memory-hard algorithm designed to resist GPU and ASIC attacks. SikkerKey enforces a minimum of 12 characters with at least one digit and one special character. Plaintext passwords are never stored or logged.

Two-Factor Authentication

TOTP secrets (the shared key your authenticator app uses) are encrypted at rest with AES-256-GCM and decrypted only during code verification.

Recovery codes are hashed with Argon2id, the same algorithm used for passwords. The plaintext codes are shown once during setup and never stored.

Sessions

Refresh tokens are generated as 32 cryptographically random bytes. Only the SHA-256 hash is stored in the database; the raw token lives only in an HttpOnly, SameSite cookie.

Password Reset and Email Verification

Password reset tokens and email verification codes follow the same pattern: a random value is generated, hashed, and stored. The plaintext is delivered to the user, by email or shown once, and the database holds only the hash.

Reset tokens expire after 1 hour. Verification codes expire after 10 minutes. Both are single-use.

File Attachments

Support ticket attachments are encrypted at rest with AES-256-GCM before being written to disk. Each file gets a fresh random initialization vector, and files are stored under UUID filenames, so the original filename is never written to disk.

What's Stored at Rest

DataStored as
SecretsEncrypted blobs (AES-256-GCM)
Project master keysEncrypted; unwrapped only through the isolated infrastructure that holds the root key
PasswordsArgon2id hashes
TOTP secretsAES-256-GCM ciphertext
Session tokensSHA-256 hashes
Machine keysPublic keys only
AttachmentsAES-256-GCM ciphertext on disk

No plaintext secret material is stored in the database or on disk.