UNPKG

timebasedcipher

Version:

Time-based key generation and AES encryption/decryption SDK

209 lines (140 loc) 5.93 kB
# timebasedcipher A lightweight, isomorphic (**Node + Browser**) library for **time-based rotating AES encryption** with optional **JWT-based key validation**. Built with [`crypto-js`](https://www.npmjs.com/package/crypto-js), this package provides a simple interface to: - Generate **time-based rotating AES keys** - Encrypt and decrypt JavaScript objects or strings - Validate JWTs before key derivation (optional) - Works seamlessly in both **frontend** and **backend** environments --- ## Installation ```bash npm install timebasedcipher crypto-js # or yarn add timebasedcipher crypto-js # or pnpm add timebasedcipher crypto-js ``` --- ## Quick Start ```ts import { generateKey, encrypt, decrypt } from "timebasedcipher"; const sharedSecret = "mySuperSecret"; const intervalSeconds = 60; // key changes every 60 seconds // Step 1: Generate a rotating key const key = generateKey(sharedSecret, intervalSeconds); console.log("Generated Key:", key); // Step 2: Encrypt some data const data = { user: "Deb", role: "admin", timestamp: Date.now() }; const cipher = encrypt(data, key); console.log("Encrypted:", cipher); // Step 3: Decrypt it const decrypted = decrypt(cipher, key); console.log("Decrypted:", decrypted); ``` Works in both **Node.js** and **browser** environments. --- ## Function Reference ### `generateKey(sharedSecretOrJwt: string, interval: number, isJwt?: boolean): string` Generates a **SHA-256 key** that rotates every `interval` seconds. When `isJwt` is set to `true`, the input is treated as a **JWT string** its `exp` claim is validated before key derivation. | Parameter | Type | Description | | -------------------- | --------- | --------------------------------------------------------------------------- | | `sharedSecretOrJwt` | `string` | A pre-shared secret or a JWT string when `isJwt = true`. | | `interval` | `number` | Time in seconds after which the key rotates. | | `isJwt` _(optional)_ | `boolean` | When `true`, validates JWT expiry and uses the raw JWT as the secret input. | **Returns:** `string` a 64-character hex string (256-bit key). **Throws:** - `Error("Invalid JWT: missing payload part")` malformed token - `Error("JWT payload does not contain a valid 'exp' claim")` - `Error("JWT is expired")` #### Example (with JWT validation) ```ts const jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."; // your JWT const interval = 120; const key = generateKey(jwt, interval, true); // validates exp claim ``` --- ### `encrypt(data: any, encryptionKeyHex: string): string` Encrypts any serializable JavaScript object or string using **AES-256-CBC**. | Parameter | Type | Description | | ------------------ | -------- | ------------------------------------------------- | | `data` | `any` | The object or value to encrypt. | | `encryptionKeyHex` | `string` | 64-character hex string key (from `generateKey`). | **Returns:** A string in format: ``` cipherHex:ivHex ``` --- ### `decrypt(cipherText: string, encryptionKeyHex: string): any` Decrypts ciphertext previously produced by `encrypt`. | Parameter | Type | Description | | ------------------ | -------- | ------------------------------------------------------- | | `cipherText` | `string` | Ciphertext in `"cipherHex:ivHex"` format. | | `encryptionKeyHex` | `string` | 64-character hex string key (same key used to encrypt). | **Returns:** The decrypted JavaScript value (automatically parsed from JSON). **Throws:** - `Error("Invalid cipher format, expected cipherHex:ivHex")` - `Error("Decryption produced empty string")` - `Error("Unable to decrypt: no valid key found or invalid payload")` --- ## ⚙️ How It Works - The key **rotates** every defined interval (e.g., every 60 seconds) - Derived using: ``` SHA256(`${secretInput}:${timeSlot}`) ``` where `timeSlot = floor(Date.now() / (interval * 1000) + 1000)` - AES encryption uses: - **AES-256-CBC** - **PKCS#7 padding** - **Random 16-byte IV** - Encrypted output format: ``` <cipherHex>:<ivHex> ``` **Both ends** must: - Use the **same secret** (or JWT) - Use the **same rotation interval** - Have **roughly synchronized clocks** (within ±1 interval) --- ## Handling Key Rotation Drift If decryption fails due to slight clock drift, try nearby intervals: ```ts const now = Date.now(); const interval = 60; const secret = "mySuperSecret"; const currentKey = generateKey(secret, interval); const prevKey = generateKey(secret, interval); // simulate earlier slot const nextKey = generateKey(secret, interval); // simulate next slot try { return decrypt(cipher, currentKey); } catch { try { return decrypt(cipher, prevKey); } catch { return decrypt(cipher, nextKey); } } ``` --- ## Browser + Node Compatibility | Environment | Supported | Notes | | --------------- | --------- | ------------------------------------------ | | Node.js | | Uses `crypto-js`, no native crypto needed | | React / Browser | | Fully supported | | Next.js | | Works in both server and client components | --- ## Security Notes - AES-256-CBC provides **confidentiality**, not integrity consider adding an **HMAC** if you need tamper detection. - Avoid embedding secrets in frontend code end users can access them. - JWT mode only validates the `exp` claim. --- ## Requirements - Node.js 14 or any modern browser - `crypto-js` dependency (installed automatically) --- ## License MIT License © 2025 [Deb Kalyan Mohanty](https://github.com/debkalyanmohanty)