DEV Community

Cover image for How to Build a Time-Locked Secret Vault (Applied Cryptography in Node.js)
Ayoola Damisile
Ayoola Damisile

Posted on

How to Build a Time-Locked Secret Vault (Applied Cryptography in Node.js)

The concept of a "Digital Time Capsule" sounds simple: write a message today, and lock it so it can’t be read until a specific date in the future.

But from an engineering perspective, how do you actually build this securely? How do you ensure that even if someone gets full access to your database, they still can’t read the messages before the unlock date?

I recently explored this by building Time Capsule, a full-stack platform using React, Node.js, and Express that allows users to create scheduled, time-locked secret message vaults.

⏳ TimeCapsule Lock

Lock Messages, Voice Notes, Photos, Spotify Soundtracks & Predictions for the Future.
A high-aesthetic Progressive Web App (PWA) that securely locks digital memories with live ticking countdowns, teaser modes, reaction cams, and celebratory reveals.

License: MIT PWA Ready Deploy with Vercel


✨ Features

  • 🔒 Cryptographic / Time-Locked Capsules: Create private digital time capsules locked until a specific future date and time (days, months, or years ahead).
  • 🎙️ Voice Notes & Audio Memos: Record voice messages directly in the browser to listen to your future self or loved ones.
  • 📸 Photo Memories & Predictions: Attach images and interactive prediction checklists that verify how accurate your forecasts were.
  • 🎵 Spotify Soundtrack Tagging: Pair every time capsule with a memorable song using Spotify embed links.
  • 🔍 Teaser Mode: Reveal subtle encrypted hints and metadata without unlocking the sealed payload ahead of time.
  • 🎥 Reaction Cam: Capture live webcam reactions and expressions…

Here is a technical breakdown of how I used Node.js native cryptography to lock data through time.

🏗️ The Architecture: Locking Data Securely

If you just save a message in a database with a column unlock_date = '2027-01-01', it isn't truly locked. Anyone with database access can just query the text. To build a true Time Capsule, the data must be cryptographically scrambled at rest.

1. AES-256-GCM Encryption

To lock the messages, I used the native Node.js crypto module. Specifically, I used AES-256-GCM (Advanced Encryption Standard in Galois/Counter Mode).

Unlike older encryption modes (like CBC), GCM doesn't just encrypt your data—it also authenticates it. It generates an Auth Tag that ensures no one has tampered with the encrypted string while it was sitting in the database.

Here is how the core encryption engine works:

javascript
const crypto = require('crypto');
// The encryption engine
function sealTimeCapsule(message, secretKey) {
    // Generate a random Initialization Vector (IV)
    const iv = crypto.randomBytes(16);

    // Create the cipher using AES-256-GCM
    const cipher = crypto.createCipheriv('aes-256-gcm', Buffer.from(secretKey), iv);

    // Encrypt the message
    let encryptedMessage = cipher.update(message, 'utf8', 'hex');
    encryptedMessage += cipher.final('hex');

    // Extract the Auth Tag for tamper-proofing
    const authTag = cipher.getAuthTag().toString('hex');

    return {
        iv: iv.toString('hex'),
        encryptedMessage: encryptedMessage,
        authTag: authTag
    };
}
Enter fullscreen mode Exit fullscreen mode
  1. The Storage Dilemma

When the function above runs, you get three things: the encryptedMessage, the iv, and the authTag.

These three pieces of data are safely stored in the PostgreSQL database alongside the unlock_date. Because the secretKey is strictly kept on the server environment (and never stored in the database row), the message is completely unreadable at rest.

  1. The Temporal Lock (Time-Based Access)

When a user attempts to read a capsule, the API doesn't just fetch the database row. It enforces a strict temporal check on the server side before it even attempts to boot up the decryption function.

javascript
// Time-lock validation middleware
function attemptUnlock(capsuleRecord) {
    const now = new Date();
    const unlockDate = new Date(capsuleRecord.unlock_date);
    if (now < unlockDate) {
        throw new Error(`Temporal Lock Active. This capsule cannot be opened until ${unlockDate}`);
    }
    // If time has passed, proceed to decrypt...
    return decryptTimeCapsule(capsuleRecord);
}
Enter fullscreen mode Exit fullscreen mode

🚀 Why This Matters

Cryptography is notoriously difficult to implement correctly, but learning how to use native tools like Node's crypto module is a massive level-up for any backend engineer.

By combining AES-256-GCM with strict temporal server checks, Time Capsule guarantees that your secrets stay secrets—no matter who is looking at the database.

💻 Try it out

I’ve open-sourced the entire platform. If you are learning how to implement encryption in Node.js, or if you just want to send a secure message to your future self, feel free to fork the code.

TIME-CAPSULE

If you found this breakdown on applied cryptography helpful, I would love a star on the repository!

About the Author Ayoola Damisile is a Full-Stack Software Engineer & Open Source Architect. Connect with me on LinkedIn
or check out my other projects at www.damisile.name.ng
.

Top comments (0)