cryptoscreen

Security Resources

Security architecture for one-time iPhone notes.

cryptoscreen is built around local encryption, PIN-gated opening, short-lived server rows, and explicit limits. This page explains what is protected, what the server stores, and where the trust boundary ends.

01

Security basics

The message is sealed before upload.

The sender writes the note in the iPhone app. The app derives the content key locally from the link secret and six-digit PIN, encrypts the plaintext, and uploads only encrypted bytes plus the metadata needed to enforce expiry and PIN attempts.

The URL fragment after #s= carries the link secret. Browsers do not send that fragment to the Worker in normal HTTP requests, so the server receives the message id but not the decryption secret.

The PIN is not stored by cryptoscreen. The app sends a PIN proof so the Worker can decide whether to release the encrypted payload without learning the PIN or plaintext.

02A

AES-GCM message encryption

Message text is encrypted with Apple CryptoKit AES.GCM. The API stores ciphertext, nonce, tag, and salt separately.

02B

HKDF-SHA256 key derivation

The content key is derived from a 32-byte link secret, the normalized six-digit PIN, and a 16-byte per-message salt using HKDF-SHA256.

02C

PIN verifier separation

The online PIN proof uses a separate HKDF-SHA256 context and is stored by the Worker only after applying a server-side pepper.

02D

Image attachment wrapping

Image attachments use a random 32-byte file key. The image is encrypted with that key, then the file key is encrypted with the message key.

03

Storage and deletion

The server stores enough to enforce one controlled read.

Neon stores encrypted message bytes, nonce, tag, salt, read policy, expiry time, failed attempt count, and a server-peppered PIN verifier. Cloudflare R2 stores encrypted image object bytes when an image is attached.

User message rows delete after one successful read, after the third wrong PIN attempt, when the sender expires the message, or after 30 days if unopened. Encrypted attachment objects are removed after their one-time download or scheduled cleanup.

cryptoscreen keeps minimal delivery status so the app can show whether a sent message was consumed, expired, destroyed, or reported a screenshot event when reciprocal interaction status is enabled. That status does not include plaintext, image plaintext, PINs, link secrets, sender contacts, or recipient contacts.

04

Operational security

The public site and API run behind strict browser and edge controls.

  • No ad SDKs, tracking SDKs, third-party analytics SDKs, accounts, or contact upload.
  • Security headers include a restrictive Content Security Policy, no-referrer policy, HSTS, and frame blocking.
  • The Cloudflare Worker validates request sizes, payload formats, attachment types, UUIDs, TTL bounds, and supported image content types.
  • Application logs must not intentionally include plaintext, PINs, PIN proofs, full message links, or raw image data.
05A

Designed to protect

Message plaintext, raw image bytes, link secrets, PIN values, and one-time read behavior from routine server-side access or database-only compromise.

05B

Required assumptions

The sender and recipient devices are trusted while encrypting or reading, iOS CryptoKit behaves correctly, and the delivered app build has not been maliciously modified.

05C

Best-effort protections

Screenshot and screen recording responses reduce accidental exposure. iOS reports screenshots after capture, and external cameras cannot be detected.

05D

Not covered

Compromised devices, malicious recipients, external cameras, phishing, social engineering, copied content after display, or link/PIN sharing with the wrong person.

Technical integrity

Security claims should stay measurable.

cryptoscreen does not promise magic disappearing text. It promises a narrower system: encrypt locally, avoid server plaintext, release encrypted payloads only after a correct PIN proof, consume normal links once, and be clear about the limits.