Insights

How Quickburn Encrypts Your Secret

Inside look at the Web Crypto and key handling that power Quickburn.

By Quickburn Team · · 4 min read

cryptoweb

Sharing a password or recovery code should not require trusting someone else's server. Quickburn was built on that premise. Every secret you create is encrypted in your own browser before it ever touches the network. This article walks through the exact steps, the algorithms we chose, and the threat model that guides our decisions.

Generating a strong key

When you type a message and click Create, Quickburn calls the Web Crypto API to generate a random 256‑bit key. We use crypto.getRandomValues with a Uint8Array to ensure high‑entropy randomness supplied by the operating system. The key is immediately base64‑url encoded and stored only in memory.

const keyBytes = new Uint8Array(32);
crypto.getRandomValues(keyBytes);
const key = await crypto.subtle.importKey('raw', keyBytes, 'AES-GCM', true, ['encrypt', 'decrypt']);

The encryption key never leaves your device. Instead, after encryption we embed it in the URL fragment — the part after the #. Browsers do not send fragments to servers, which means our backend never sees it. Anyone intercepting network traffic sees only the encrypted payload.

AES‑GCM and authenticated encryption

Quickburn uses AES‑GCM for its combination of speed and built‑in integrity checks. GCM, or Galois/Counter Mode, produces a ciphertext and an authentication tag. The tag ensures that any tampering with the ciphertext can be detected during decryption. We generate a 96‑bit nonce for each message and store it alongside the ciphertext.

const iv = crypto.getRandomValues(new Uint8Array(12));
const cipherBuffer = await crypto.subtle.encrypt(
  { name: 'AES-GCM', iv },
  key,
  new TextEncoder().encode(message)
);

The server receives only cipherBuffer, the nonce (iv), and metadata such as the expiry time. No plaintext, no keys. If the server is compromised, attackers gain nothing useful without the key fragment.

Sharing via URL fragment

After encryption, Quickburn constructs a URL like https://example.com/#<key>. The key is encoded and appended after the # symbol. Because fragments are handled entirely by the browser, they never appear in HTTP requests. When you send the link to someone, they receive both the page URL and the key in one package.

On the server side we generate a random identifier for the encrypted blob and return it to the browser. The final shareable link looks like https://example.com/b/abcd#<key>, where abcd is the blob ID. The key fragment is needed to decrypt; without it, the blob is useless data.

Decryption flow

When a recipient visits the link, their browser loads a small script that reads the key from location.hash, fetches the ciphertext for abcd, and runs the inverse of the encryption process. If decryption succeeds, the plaintext is displayed and the browser immediately sends a delete request to remove the blob from the server. If anything goes wrong — invalid tag, missing key, expired link — the secret is never shown.

Threat model and assumptions

Quickburn’s approach mitigates many common risks but cannot cover every scenario. We assume the browser environment is trustworthy and that HTTPS is used end‑to‑end. If an attacker controls the recipient's device or installs malicious extensions, they could capture the secret after decryption. Similarly, if the sender shares the link over an insecure channel, the key fragment might leak.

We also assume the server behaves honestly in terms of deletion. While the server never receives the key, it does hold the encrypted blob until expiry. To limit exposure we store blobs in a dedicated database table with strict retention policies and run periodic cleanup jobs. Future work includes offering client‑side verification that a delete request succeeded.

Why not PGP or Signal?

Quickburn is not a replacement for full‑fledged secure messaging systems. Tools like PGP or Signal provide long‑term identity, forward secrecy, and message authenticity. Our goal is narrower: ephemeral, one‑off sharing with minimal friction. For that we prioritize ease of use and the guarantee that secrets vanish quickly. The entire codebase fits in a few kilobytes, making it easy to audit.

Future improvements

We plan to add optional password layers, allowing the sender to require a second secret before decryption. We are also exploring WebAssembly implementations of modern ciphers like XChaCha20‑Poly1305 for even stronger security on older devices.

Quickburn aims for transparency so you can verify our claims. If you have ideas or find bugs, let us know. Security is a journey, and we welcome the community’s help in keeping Quickburn trustworthy.

Keep exploring

Create a secret