timebasedcipher 3.0.1 → 3.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,187 +1,147 @@
1
1
  # timebasedcipher
2
2
 
3
- A lightweight, isomorphic (**Node + Browser**) library for **time-based rotating AES encryption with integrity protection**.
3
+ A lightweight, isomorphic (**Node.js 18+ and modern browsers**) library
4
+ for **time-based rotating AES-256-GCM encryption with integrity
5
+ validation**.
4
6
 
5
- Built with [`crypto-js`](https://www.npmjs.com/package/crypto-js), this package provides:
7
+ This implementation uses the **Web Crypto API** and provides:
6
8
 
7
- - **Time-based rotating AES-256 keys**
8
- - **AES-256-CBC encryption**
9
- -️ **HMAC-SHA256 integrity & tamper detection**
10
- - **Application-level domain separation (`appName`)**
11
- - Works in **Node.js and browser environments**
9
+ - Time-based rotating AES-256 keys derived using HKDF-SHA256
10
+ - Authenticated encryption using AES-256-GCM
11
+ - Encrypted signature validation
12
+ - Works in both Node.js (v18+) and modern browser environments
13
+ - No external crypto dependencies
12
14
 
13
15
  ---
14
16
 
15
17
  ## Installation
16
18
 
17
19
  ```bash
18
- npm install timebasedcipher crypto-js
20
+ npm install timebasedcipher
19
21
  # or
20
- yarn add timebasedcipher crypto-js
22
+ yarn add timebasedcipher
21
23
  # or
22
- pnpm add timebasedcipher crypto-js
24
+ pnpm add timebasedcipher
23
25
  ```
24
26
 
27
+ Node.js 18+ is required for native Web Crypto support.
28
+
25
29
  ---
26
30
 
27
31
  ## Quick Start
28
32
 
29
33
  ```ts
30
- import { generateKey, encrypt, decrypt } from "timebasedcipher";
34
+ import { encrypt, decrypt } from "timebasedcipher";
31
35
 
32
- const sharedSecret = "mySuperSecret";
36
+ const secret = "mySuperSecret";
33
37
  const intervalSeconds = 60; // key rotates every 60 seconds
34
38
 
35
- // Generate a rotating key
36
- const key = generateKey(sharedSecret, intervalSeconds);
39
+ const data = { user: "TestUser", role: "admin", timestamp: Date.now() };
37
40
 
38
- // Encrypt data
39
- const data = { user: "Deb", role: "admin", timestamp: Date.now() };
40
- const cipher = encrypt(data, key);
41
+ // Encrypt
42
+ const cipher = await encrypt(data, secret, intervalSeconds);
41
43
 
42
- // Decrypt data
43
- const decrypted = decrypt(cipher, key);
44
+ // Decrypt
45
+ const decrypted = await decrypt(cipher, secret, intervalSeconds);
44
46
 
45
47
  console.log(decrypted);
46
48
  ```
47
49
 
48
- Works seamlessly in both **Node.js** and **browser** environments.
49
-
50
50
  ---
51
51
 
52
- ## Function Reference
53
-
54
- ---
55
-
56
- ### `generateKey(sharedSecretOrJwt: string, interval: number): string`
57
-
58
- Generates a **SHA-256–derived rotating key** that changes every `interval` seconds.
59
-
60
- - The input can be a **shared secret** or a **JWT string**
61
- - JWTs are treated as **opaque entropy**
62
- - **JWT validation (exp, signature)** is expected to be handled upstream
63
-
64
- #### Parameters
65
-
66
- | Name | Type | Description |
67
- | ------------------- | -------- | ----------------------------- |
68
- | `sharedSecretOrJwt` | `string` | A shared secret or JWT string |
69
- | `interval` | `number` | Rotation interval in seconds |
70
-
71
- #### Returns
72
-
73
- - `string` — 64-character hex string (32-byte AES-256 key)
74
-
75
- #### Key Derivation
76
-
77
- ```text
78
- SHA256(`${secretInput}:${timeSlot}`)
79
- ```
52
+ ## API Reference
80
53
 
81
- Where:
54
+ ### encrypt`<T>`{=html}(data: T, secret: string, intervalSeconds: number): Promise`<string>`{=html}
82
55
 
83
- ```text
84
- timeSlot = floor(Date.now() / (interval * 1000) + 1000)
85
- ```
56
+ Encrypts JSON-serializable data using a time-rotating AES-256-GCM key.
86
57
 
87
58
  ---
88
59
 
89
- ### `encrypt(data: any, encryptionKeyHex: string, appName?: string): string`
60
+ | Name | Type | Description |
61
+ | ----------------- | -------- | ------------------------------------- |
62
+ | `data` | `any` | JSON-serializable value |
63
+ | `secret` | `string` | Shared secret used for key derivation |
64
+ | `intervalSeconds` | `number` | Key rotation interval in seconds |
90
65
 
91
- Encrypts data using **AES-256-CBC** and appends an **HMAC-SHA256** for integrity.
66
+ ---
92
67
 
93
- #### Parameters
68
+ **Returns**
94
69
 
95
- | Name | Type | Description |
96
- | ---------------------- | -------- | ---------------------------------- |
97
- | `data` | `any` | Any JSON-serializable value |
98
- | `encryptionKeyHex` | `string` | 64-char hex key from `generateKey` |
99
- | `appName` _(optional)_ | `string` | Application context |
70
+ `Promise<string>` --- Ciphertext string.
100
71
 
101
- #### Returns
72
+ ---
102
73
 
103
- A ciphertext string in the format:
74
+ ### decrypt`<T>`{=html}(payload: string, secret: string, intervalSeconds: number): Promise`<T>`{=html}
104
75
 
105
- ```text
106
- cipherHex:ivHex:hmacHex
107
- ```
76
+ Decrypts and validates ciphertext produced by `encrypt`.
108
77
 
109
78
  ---
110
79
 
111
- ### `decrypt(cipherText: string, encryptionKeyHex: string, appName?: string): any`
112
-
113
- Decrypts and verifies ciphertext produced by `encrypt`.
114
-
115
- #### Parameters
80
+ | Name | Type | Description |
81
+ | ----------------- | -------- | ----------------------------------------- |
82
+ | `payload` | `string` | Encrypted string (`sigCipher:iv:data:iv`) |
83
+ | `secret` | `string` | Same shared secret used during encryption |
84
+ | `intervalSeconds` | `number` | Same rotation interval used during |
116
85
 
117
- | Name | Type | Description |
118
- | ---------------------- | -------- | -------------------------------------------- |
119
- | `cipherText` | `string` | Encrypted string (`cipherHex:ivHex:hmacHex`) |
120
- | `encryptionKeyHex` | `string` | Same key used during encryption |
121
- | `appName` _(optional)_ | `string` | Must match encryption appName |
86
+ ---
122
87
 
123
- #### Returns
88
+ **Returns**
124
89
 
125
- - Original decrypted JavaScript value (parsed from JSON)
90
+ `Promise<T>` --- Decrypted JavaScript value.
126
91
 
127
- #### Throws
92
+ **Throws**
128
93
 
129
94
  - `Error("Invalid cipher format")`
130
- - `Error("Invalid HMAC: ciphertext may be tampered")`
131
- - `Error("Unable to decrypt")`
95
+ - `Error("Invalid signature")`
96
+ - Decryption errors if authentication fails
132
97
 
133
98
  ---
134
99
 
135
- ## Application Context (`appName`)
136
-
137
- `appName` provides **cryptographic domain separation**.
100
+ ## Key Derivation
138
101
 
139
- - Prevents ciphertexts from being reused across apps
140
- - Prevents MAC key reuse
102
+ Keys are derived using:
141
103
 
142
- ### Example
104
+ - HKDF with SHA-256
105
+ - Salt = current time slot
106
+ - Info = "time-based-encryption"
143
107
 
144
- ```ts
145
- const key = generateKey(secret, 60);
108
+ Time slot calculation:
146
109
 
147
- const cipher = encrypt(data, key, "billing-service");
148
- const plain = decrypt(cipher, key, "billing-service");
149
- ```
110
+ timeSlot = floor(Date.now() / (intervalSeconds * 1000))
150
111
 
151
- Using a different `appName` will **fail decryption**.
112
+ A new encryption key is automatically derived for each time window.
152
113
 
153
114
  ---
154
115
 
155
- ## Browser + Node Compatibility
116
+ ## Security Model
156
117
 
157
- | Environment | Supported | Notes |
158
- | --------------- | --------- | -------------------------- |
159
- | Node.js | ✅ | Uses `crypto-js` |
160
- | Browser | ✅ | Fully supported |
161
- | React / Next.js | ✅ | Works client & server-side |
118
+ - Uses AES-256-GCM (authenticated encryption)
119
+ - Provides built-in integrity and tamper detection
120
+ - Includes encrypted signature validation
121
+ - No manual HMAC required (GCM provides authentication)
122
+ - Requires loosely synchronized clocks between encrypting and
123
+ decrypting systems
162
124
 
163
125
  ---
164
126
 
165
- ## Security Notes
127
+ ## Environment Support
166
128
 
167
- - Uses **Encrypt-then-MAC** (AES + HMAC) — secure against tampering
168
- - `appName` ensures **cross-application isolation**
169
- - JWTs are treated as entropy only — **authentication must happen elsewhere**
170
- - Do **not** embed secrets in frontend code
171
- - Requires roughly synchronized clocks
129
+ | Name | Supported |
130
+ | ----------------- | --------- |
131
+ | `Node.js 18+` | Yes |
132
+ | `Modern Browsers` | Yes |
133
+ | `React / Next.js` | Yes |
172
134
 
173
135
  ---
174
136
 
175
137
  ## Requirements
176
138
 
177
- - Node.js 14 or modern browser
178
- - `crypto-js` dependency
139
+ - Node.js 18+ or modern browser with Web Crypto API
140
+ - No external cryptography libraries required
179
141
 
180
142
  ---
181
143
 
182
144
  ## License
183
145
 
184
- MIT License © 2026
185
- [**Deb Kalyan Mohanty**](https://github.com/debkalyanmohanty)
186
-
187
- ---
146
+ MIT License © 2026\
147
+ [Deb Kalyan Mohanty](https://github.com/debkalyanmohanty)
package/dist/index.d.ts CHANGED
@@ -1,38 +1,30 @@
1
1
  /**
2
- * Generate a time-based rotating key using SHA-256.
2
+ * Time-Based Cipher with Encrypted Signature
3
3
  *
4
- * The key is derived as:
5
- * SHA256(`${secretInput}:${timeSlot}`)
4
+ * Format:
5
+ * sigCipherHex:sigIvHex:dataCipherHex:dataIvHex
6
6
  *
7
- * Notes:
8
- * - If `sharedSecretOrJwt` is a JWT, it is treated as opaque input
9
- * - JWT validation (signature / exp) is assumed to be handled elsewhere
10
- * - This function is purely a key-derivation utility
7
+ * Requirements:
8
+ * - Node.js 18+
9
+ * - Modern browsers
11
10
  */
12
- export declare const generateKey: (sharedSecretOrJwt: string, interval: number) => string;
13
11
  /**
14
- * Encrypt arbitrary data using:
15
- * - AES-256-CBC (confidentiality)
16
- * - HMAC-SHA256 (integrity & authenticity)
12
+ * Encrypt JSON data with encrypted signature.
17
13
  *
18
- * Cipher format:
19
- * cipherHex:ivHex:hmacHex
14
+ * @param data - JSON-serializable data.
15
+ * @param secret - Shared secret.
16
+ * @param intervalSeconds - Rotation interval in seconds.
20
17
  *
21
- * `appName`:
22
- * - Included ONLY in HMAC key derivation
23
- * - Ensures ciphertexts are bound to an application context
24
- * - Must match during decryption
18
+ * @returns Promise resolving to ciphertext string.
25
19
  */
26
- export declare const encrypt: (data: any, encryptionKeyHex: string, appName?: string) => string;
20
+ export declare function encrypt<T>(data: T, secret: string, intervalSeconds: number): Promise<string>;
27
21
  /**
28
- * Decrypt data encrypted by {@link encrypt}.
22
+ * Decrypt ciphertext with encrypted signature validation.
29
23
  *
30
- * Steps:
31
- * 1. Parse cipher format
32
- * 2. Recompute and verify HMAC (tamper detection)
33
- * 3. Decrypt AES-256-CBC
34
- * 4. Parse JSON payload
24
+ * @param payload - Ciphertext string.
25
+ * @param secret - Shared secret.
26
+ * @param intervalSeconds - Rotation interval.
35
27
  *
36
- * `appName` MUST match the value used during encryption.
28
+ * @returns Promise resolving to decrypted data.
37
29
  */
38
- export declare const decrypt: (cipherText: string, encryptionKeyHex: string, appName?: string) => unknown;
30
+ export declare function decrypt<T>(payload: string, secret: string, intervalSeconds: number): Promise<T>;
package/dist/index.js CHANGED
@@ -1,134 +1,122 @@
1
1
  "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.decrypt = exports.encrypt = exports.generateKey = void 0;
7
- const crypto_js_1 = __importDefault(require("crypto-js"));
8
2
  /**
9
- * Decode the payload of a JWT without verifying its signature.
10
- * Used only to read the `exp` claim (seconds since epoch).
3
+ * Time-Based Cipher with Encrypted Signature
4
+ *
5
+ * Format:
6
+ * sigCipherHex:sigIvHex:dataCipherHex:dataIvHex
11
7
  *
12
- * ⚠️ This does NOT verify authenticity — only structure and expiry.
8
+ * Requirements:
9
+ * - Node.js 18+
10
+ * - Modern browsers
13
11
  */
14
- const decodeJwtPayload = (token) => {
15
- const parts = token.split(".");
16
- if (parts.length < 2) {
17
- throw new Error("Invalid JWT: missing payload part");
18
- }
19
- const base64Url = parts[1];
20
- const base64 = base64Url.replace(/-/g, "+").replace(/_/g, "/");
21
- const wordArray = crypto_js_1.default.enc.Base64.parse(base64);
22
- const json = wordArray.toString(crypto_js_1.default.enc.Utf8);
23
- try {
24
- return JSON.parse(json);
12
+ Object.defineProperty(exports, "__esModule", { value: true });
13
+ exports.encrypt = encrypt;
14
+ exports.decrypt = decrypt;
15
+ const cryptoObj = (() => {
16
+ if (typeof globalThis !== "undefined" && globalThis.crypto) {
17
+ return globalThis.crypto;
25
18
  }
26
- catch {
27
- throw new Error("Invalid JWT payload JSON");
19
+ throw new Error("Web Crypto API not available. Requires Node 18+ or modern browser.");
20
+ })();
21
+ const encoder = new TextEncoder();
22
+ const decoder = new TextDecoder();
23
+ /**
24
+ * Convert ArrayBuffer to hex string.
25
+ */
26
+ function toHex(buffer) {
27
+ return Array.from(new Uint8Array(buffer))
28
+ .map((b) => b.toString(16).padStart(2, "0"))
29
+ .join("");
30
+ }
31
+ /**
32
+ * Convert hex string to ArrayBuffer.
33
+ */
34
+ function hexToBuffer(hex) {
35
+ if (!/^[0-9a-fA-F]+$/.test(hex) || hex.length % 2 !== 0) {
36
+ throw new Error("Invalid hex string");
28
37
  }
29
- };
38
+ const bytes = new Uint8Array(hex.match(/.{1,2}/g).map((b) => parseInt(b, 16)));
39
+ return bytes.buffer;
40
+ }
30
41
  /**
31
- * Derive a dedicated HMAC key from the encryption key.
32
- *
33
- * `appName` acts as cryptographic context (domain separation):
34
- * - Different apps using the same encryption key will NOT share MAC keys
35
- * - Prevents cross-application replay or substitution attacks
36
- *
37
- * Default appName = "timebasedcipher" for backward compatibility.
42
+ * Derive AES-256-GCM key using HKDF-SHA256.
38
43
  */
39
- const deriveHmacKeyHex = (encryptionKeyHex, appName = "timebasedcipher") => {
40
- return crypto_js_1.default.SHA256(`${appName}-hmac:${encryptionKeyHex}`).toString(crypto_js_1.default.enc.Hex);
41
- };
44
+ async function deriveKey(secret, intervalSeconds) {
45
+ if (!secret)
46
+ throw new Error("Secret must not be empty");
47
+ if (intervalSeconds <= 0)
48
+ throw new Error("intervalSeconds must be positive");
49
+ const now = Date.now() - 1000;
50
+ const timeSlot = Math.floor(now / (intervalSeconds * 1000));
51
+ const baseKey = await cryptoObj.subtle.importKey("raw", encoder.encode(secret).buffer, { name: "HKDF" }, false, ["deriveKey"]);
52
+ return cryptoObj.subtle.deriveKey({
53
+ name: "HKDF",
54
+ hash: "SHA-256",
55
+ salt: encoder.encode(String(timeSlot)).buffer,
56
+ info: encoder.encode("time-based-encryption").buffer,
57
+ }, baseKey, { name: "AES-GCM", length: 256 }, false, ["encrypt", "decrypt"]);
58
+ }
42
59
  /**
43
- * Generate a time-based rotating key using SHA-256.
44
- *
45
- * The key is derived as:
46
- * SHA256(`${secretInput}:${timeSlot}`)
47
- *
48
- * Notes:
49
- * - If `sharedSecretOrJwt` is a JWT, it is treated as opaque input
50
- * - JWT validation (signature / exp) is assumed to be handled elsewhere
51
- * - This function is purely a key-derivation utility
60
+ * Encrypt raw ArrayBuffer with AES-GCM.
52
61
  */
53
- const generateKey = (sharedSecretOrJwt, interval) => {
54
- const timeSlot = Math.floor(Date.now() / (interval * 1000) + 1000);
55
- const input = `${sharedSecretOrJwt}:${timeSlot}`;
56
- return crypto_js_1.default.SHA256(input).toString(crypto_js_1.default.enc.Hex);
57
- };
58
- exports.generateKey = generateKey;
62
+ async function aesEncrypt(key, data) {
63
+ const ivBytes = cryptoObj.getRandomValues(new Uint8Array(12));
64
+ const iv = ivBytes.buffer;
65
+ const cipher = await cryptoObj.subtle.encrypt({ name: "AES-GCM", iv }, key, data);
66
+ return { cipher, iv };
67
+ }
59
68
  /**
60
- * Encrypt arbitrary data using:
61
- * - AES-256-CBC (confidentiality)
62
- * - HMAC-SHA256 (integrity & authenticity)
69
+ * Decrypt raw ArrayBuffer with AES-GCM.
70
+ */
71
+ async function aesDecrypt(key, cipher, iv) {
72
+ return cryptoObj.subtle.decrypt({ name: "AES-GCM", iv }, key, cipher);
73
+ }
74
+ /**
75
+ * Encrypt JSON data with encrypted signature.
63
76
  *
64
- * Cipher format:
65
- * cipherHex:ivHex:hmacHex
77
+ * @param data - JSON-serializable data.
78
+ * @param secret - Shared secret.
79
+ * @param intervalSeconds - Rotation interval in seconds.
66
80
  *
67
- * `appName`:
68
- * - Included ONLY in HMAC key derivation
69
- * - Ensures ciphertexts are bound to an application context
70
- * - Must match during decryption
81
+ * @returns Promise resolving to ciphertext string.
71
82
  */
72
- const encrypt = (data, encryptionKeyHex, appName = "timebasedcipher") => {
73
- const json = JSON.stringify(data);
74
- try {
75
- const key = crypto_js_1.default.enc.Hex.parse(encryptionKeyHex);
76
- const iv = crypto_js_1.default.lib.WordArray.random(16);
77
- const encrypted = crypto_js_1.default.AES.encrypt(json, key, { iv });
78
- const cipherHex = encrypted.ciphertext.toString(crypto_js_1.default.enc.Hex);
79
- const ivHex = iv.toString(crypto_js_1.default.enc.Hex);
80
- // Derive MAC key using encryption key + appName context
81
- const hmacKeyHex = deriveHmacKeyHex(encryptionKeyHex, appName);
82
- const hmacKey = crypto_js_1.default.enc.Hex.parse(hmacKeyHex);
83
- const mac = crypto_js_1.default.HmacSHA256(`${cipherHex}:${ivHex}`, hmacKey).toString(crypto_js_1.default.enc.Hex);
84
- return `${cipherHex}:${ivHex}:${mac}`;
85
- }
86
- catch (err) {
87
- console.error("Error in encrypt:", err);
88
- throw err;
89
- }
90
- };
91
- exports.encrypt = encrypt;
83
+ async function encrypt(data, secret, intervalSeconds) {
84
+ const key = await deriveKey(secret, intervalSeconds);
85
+ // Signature payload (can be customized)
86
+ const signaturePayload = encoder.encode("signature-v1").buffer;
87
+ const sigEncrypted = await aesEncrypt(key, signaturePayload);
88
+ const dataBuffer = encoder.encode(JSON.stringify(data)).buffer;
89
+ const dataEncrypted = await aesEncrypt(key, dataBuffer);
90
+ return [
91
+ toHex(sigEncrypted.cipher),
92
+ toHex(sigEncrypted.iv),
93
+ toHex(dataEncrypted.cipher),
94
+ toHex(dataEncrypted.iv),
95
+ ].join(":");
96
+ }
92
97
  /**
93
- * Decrypt data encrypted by {@link encrypt}.
98
+ * Decrypt ciphertext with encrypted signature validation.
94
99
  *
95
- * Steps:
96
- * 1. Parse cipher format
97
- * 2. Recompute and verify HMAC (tamper detection)
98
- * 3. Decrypt AES-256-CBC
99
- * 4. Parse JSON payload
100
+ * @param payload - Ciphertext string.
101
+ * @param secret - Shared secret.
102
+ * @param intervalSeconds - Rotation interval.
100
103
  *
101
- * `appName` MUST match the value used during encryption.
104
+ * @returns Promise resolving to decrypted data.
102
105
  */
103
- const decrypt = (cipherText, encryptionKeyHex, appName = "timebasedcipher") => {
104
- const parts = cipherText.split(":");
105
- if (parts.length !== 3) {
106
- throw new Error("Invalid cipher format, expected cipherHex:ivHex:hmacHex");
107
- }
108
- const [encryptedHex, ivHex, hmacHex] = parts;
109
- // Re-derive MAC key using same appName context
110
- const hmacKeyHex = deriveHmacKeyHex(encryptionKeyHex, appName);
111
- const hmacKey = crypto_js_1.default.enc.Hex.parse(hmacKeyHex);
112
- const recomputedMac = crypto_js_1.default.HmacSHA256(`${encryptedHex}:${ivHex}`, hmacKey).toString(crypto_js_1.default.enc.Hex);
113
- // Not constant-time, but acceptable for most non-hostile environments
114
- if (recomputedMac !== hmacHex) {
115
- throw new Error("Invalid HMAC: ciphertext may be tampered or key/appName is wrong");
106
+ async function decrypt(payload, secret, intervalSeconds) {
107
+ const parts = payload.split(":");
108
+ if (parts.length !== 4) {
109
+ throw new Error("Invalid cipher format");
116
110
  }
117
- const key = crypto_js_1.default.enc.Hex.parse(encryptionKeyHex);
118
- const iv = crypto_js_1.default.enc.Hex.parse(ivHex);
119
- const ciphertext = crypto_js_1.default.enc.Hex.parse(encryptedHex);
120
- const cipherParams = crypto_js_1.default.lib.CipherParams.create({ ciphertext });
121
- try {
122
- const decrypted = crypto_js_1.default.AES.decrypt(cipherParams, key, { iv });
123
- const utf8 = decrypted.toString(crypto_js_1.default.enc.Utf8);
124
- if (!utf8) {
125
- throw new Error("Decryption produced empty string");
126
- }
127
- return JSON.parse(utf8);
111
+ const [sigCipherHex, sigIvHex, dataCipherHex, dataIvHex,] = parts;
112
+ const key = await deriveKey(secret, intervalSeconds);
113
+ // Decrypt signature
114
+ const sigPlain = await aesDecrypt(key, hexToBuffer(sigCipherHex), hexToBuffer(sigIvHex));
115
+ const sigText = decoder.decode(sigPlain);
116
+ if (sigText !== "signature-v1") {
117
+ throw new Error("Invalid signature");
128
118
  }
129
- catch (err) {
130
- console.error("Error decrypting:", err);
131
- throw new Error("Unable to decrypt: invalid key, appName, or corrupted payload");
132
- }
133
- };
134
- exports.decrypt = decrypt;
119
+ // Decrypt actual data
120
+ const dataPlain = await aesDecrypt(key, hexToBuffer(dataCipherHex), hexToBuffer(dataIvHex));
121
+ return JSON.parse(decoder.decode(dataPlain));
122
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "timebasedcipher",
3
- "version": "3.0.1",
3
+ "version": "3.0.2",
4
4
  "description": "Time-based key generation and AES encryption/decryption SDK",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.js",