DEV Community

Cover image for How I built self-destructing notes with AES-256-GCM and Upstash Redis
Michael Bello
Michael Bello

Posted on

How I built self-destructing notes with AES-256-GCM and Upstash Redis

Every developer has sent credentials over Slack. The other person copies the key and it sits in chat history forever, in Slack's logs, backups, search indexes.

I built notenotfound to fix this. Here's how the encryption and burn-after-reading works.

Encryption (AES-256-GCM)

function encrypt(plaintext) {
  const key    = crypto.createHash("sha256").update(ENCRYPTION_KEY).digest();
  const iv     = crypto.randomBytes(12);   // random 96-bit IV per note
  const cipher = crypto.createCipheriv("aes-256-gcm", key, iv);
  const enc    = Buffer.concat([cipher.update(plaintext, "utf8"), cipher.final()]);
  const tag    = cipher.getAuthTag();      // 128-bit auth tag β€” tamper-proof
  return [iv, tag, enc].map(b => b.toString("hex")).join(":");
}
Enter fullscreen mode Exit fullscreen mode

GCM mode means the auth tag detects any tampering. I chose SHA-256 for key derivation because scryptSync hit Netlify's serverless CPU limits.

The burn-after-reading

Two steps: (1) confirm=false checks note exists, returns metadata, note untouched. (2) confirm=true decrypts first, THEN deletes, then returns content. If decrypt fails, note stays in Redis. User gets an error and can retry β€” note never silently disappears.

The name

notenotfound, because that's exactly what happens to your note after it's read.

Live: notenotfound.netlify.app | Code: github.com/mykelayo/notenotfound

Top comments (0)