aegis-lock 2.1.0 → 2.2.0
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 +43 -50
- package/dist/client.d.ts +13 -37
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +39 -62
- package/dist/client.js.map +1 -1
- package/dist/crypto.d.ts +10 -7
- package/dist/crypto.d.ts.map +1 -1
- package/dist/crypto.js +18 -9
- package/dist/crypto.js.map +1 -1
- package/dist/types.d.ts +1 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +13 -1
package/README.md
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
# aegis-lock
|
|
2
2
|
|
|
3
|
-
[](https://badge.fury.io/js/aegis-lock)
|
|
3
|
+
[](https://badge.fury.io/js/aegis-lock)
|
|
4
4
|
[](https://opensource.org/licenses/MIT)
|
|
5
5
|
|
|
6
|
-
**Database-agnostic client-side AES-256-GCM field-level encryption with Contextual Binding and
|
|
6
|
+
**Database-agnostic client-side AES-256-GCM field-level encryption with Contextual Binding, Blind Indexing, and Seamless Key Rotation.**
|
|
7
7
|
|
|
8
|
-
Encrypt sensitive fields before they leave the browser or server. Decrypt after select. Zero plaintext hits the wire or your database. Works with
|
|
8
|
+
Encrypt sensitive fields before they leave the browser or server. Decrypt after select. Zero plaintext hits the wire or your database. Works with Supabase, MongoDB, or any database via custom adapters.
|
|
9
9
|
|
|
10
10
|
> **⚠️ SECURITY WARNING:** `aegis-lock` provides the cryptographic primitives, but **you are responsible for your keys.** Never hardcode `CryptoKey` exports in your source code. Always use a secure Key Management Service (KMS) or strict, vault-backed environment variables to inject your keys at runtime.
|
|
11
11
|
|
|
@@ -22,17 +22,22 @@ npm install aegis-lock
|
|
|
22
22
|
|
|
23
23
|
```typescript
|
|
24
24
|
import { createClient } from "@supabase/supabase-js";
|
|
25
|
-
import { AegisClient, SupabaseAdapter,
|
|
25
|
+
import { AegisClient, SupabaseAdapter, importKey, generateBidxKey } from "aegis-lock";
|
|
26
26
|
|
|
27
27
|
const supabase = createClient(SUPABASE_URL, SUPABASE_ANON_KEY);
|
|
28
28
|
const adapter = new SupabaseAdapter(supabase);
|
|
29
29
|
|
|
30
|
-
//
|
|
31
|
-
|
|
32
|
-
const
|
|
30
|
+
// 1. Setup your Key Ring for Key Rotation
|
|
31
|
+
// You should load these base64 strings securely from your environment variables
|
|
32
|
+
const keyRing = {
|
|
33
|
+
"v1": await importKey(process.env.AEGIS_KEY_V1),
|
|
34
|
+
"v2": await importKey(process.env.AEGIS_KEY_V2) // Your newest key
|
|
35
|
+
};
|
|
36
|
+
const activeVersion = "v2";
|
|
33
37
|
|
|
34
|
-
//
|
|
38
|
+
const bidxKey = await generateBidxKey(); // Or import your saved blind index key
|
|
35
39
|
|
|
40
|
+
// 2. Initialize the Client
|
|
36
41
|
const aegis = new AegisClient({
|
|
37
42
|
adapter,
|
|
38
43
|
primaryKeyField: "record_id", // REQUIRED: Binds ciphertext to the row to prevent tampering
|
|
@@ -42,9 +47,9 @@ const aegis = new AegisClient({
|
|
|
42
47
|
bidxFields: {
|
|
43
48
|
secure_fields: ["email"] // Optional: Creates an 'email_bidx' column for searching
|
|
44
49
|
}
|
|
45
|
-
},
|
|
50
|
+
}, keyRing, activeVersion, bidxKey);
|
|
46
51
|
|
|
47
|
-
//
|
|
52
|
+
// 3. Insert — fields are auto-encrypted using the 'v2' key.
|
|
48
53
|
// Note: You MUST provide the primary key application-side!
|
|
49
54
|
await aegis.insert("secure_fields", {
|
|
50
55
|
record_id: "uuid-1234-5678",
|
|
@@ -52,20 +57,21 @@ await aegis.insert("secure_fields", {
|
|
|
52
57
|
encrypted_content: "Top secret",
|
|
53
58
|
});
|
|
54
59
|
|
|
55
|
-
//
|
|
60
|
+
// 4. Select — Aegis automatically hashes the email to search the 'email_bidx' column securely.
|
|
61
|
+
// It will dynamically select the correct key from the KeyRing to decrypt the results.
|
|
56
62
|
const { data } = await aegis.select("secure_fields", {
|
|
57
63
|
column: "email",
|
|
58
64
|
value: "alice@example.com"
|
|
59
65
|
});
|
|
60
66
|
|
|
61
|
-
//
|
|
67
|
+
// 5. Update — automatically re-encrypts with a new IV and the active 'v2' key.
|
|
62
68
|
await aegis.update("secure_fields", {
|
|
63
69
|
record_id: "uuid-1234-5678", // Must include the primary key!
|
|
64
70
|
email: "new_alice@example.com",
|
|
65
71
|
encrypted_content: "New secret"
|
|
66
72
|
});
|
|
67
73
|
|
|
68
|
-
//
|
|
74
|
+
// 6. Delete — Aegis automatically hashes the email to find the correct row to delete
|
|
69
75
|
await aegis.delete("secure_fields", {
|
|
70
76
|
column: "email",
|
|
71
77
|
value: "new_alice@example.com"
|
|
@@ -76,14 +82,14 @@ await aegis.delete("secure_fields", {
|
|
|
76
82
|
|
|
77
83
|
```typescript
|
|
78
84
|
import { MongoClient } from "mongodb";
|
|
79
|
-
import { AegisClient, MongoDBAdapter,
|
|
85
|
+
import { AegisClient, MongoDBAdapter, importKey } from "aegis-lock";
|
|
80
86
|
import { v4 as uuidv4 } from "uuid";
|
|
81
87
|
|
|
82
88
|
const mongo = new MongoClient("mongodb://localhost:27017");
|
|
83
89
|
await mongo.connect();
|
|
84
90
|
const adapter = new MongoDBAdapter(mongo.db("myapp"));
|
|
85
91
|
|
|
86
|
-
const
|
|
92
|
+
const keyRing = { "v1": await importKey(process.env.AEGIS_MASTER_KEY) };
|
|
87
93
|
|
|
88
94
|
const aegis = new AegisClient({
|
|
89
95
|
adapter,
|
|
@@ -91,36 +97,23 @@ const aegis = new AegisClient({
|
|
|
91
97
|
encryptedFields: {
|
|
92
98
|
users: ["ssn", "credit_card"]
|
|
93
99
|
}
|
|
94
|
-
},
|
|
100
|
+
}, keyRing, "v1");
|
|
95
101
|
|
|
96
102
|
const newUserId = uuidv4();
|
|
97
103
|
|
|
98
|
-
//
|
|
104
|
+
// Insert with a client-generated ID
|
|
99
105
|
await aegis.insert("users", {
|
|
100
106
|
_id: newUserId,
|
|
101
107
|
name: "Alice",
|
|
102
108
|
ssn: "123-45-6789"
|
|
103
109
|
});
|
|
104
110
|
|
|
105
|
-
//
|
|
111
|
+
// Select by an unencrypted field
|
|
106
112
|
const { data } = await aegis.select("users", {
|
|
107
113
|
column: "name",
|
|
108
114
|
value: "Alice"
|
|
109
115
|
});
|
|
110
116
|
// data[0].ssn → "123-45-6789" (decrypted)
|
|
111
|
-
|
|
112
|
-
// 3. Update — automatically re-encrypts the SSN with a new IV
|
|
113
|
-
await aegis.update("users", {
|
|
114
|
-
_id: newUserId, // Must include the primary key!
|
|
115
|
-
name: "Alice",
|
|
116
|
-
ssn: "999-99-9999"
|
|
117
|
-
});
|
|
118
|
-
|
|
119
|
-
// 4. Delete — Removes the record from the database
|
|
120
|
-
await aegis.delete("users", {
|
|
121
|
-
column: "_id",
|
|
122
|
-
value: newUserId
|
|
123
|
-
});
|
|
124
117
|
```
|
|
125
118
|
|
|
126
119
|
## Custom Adapter
|
|
@@ -152,23 +145,24 @@ class MyAdapter implements DatabaseAdapter {
|
|
|
152
145
|
|
|
153
146
|
## API
|
|
154
147
|
|
|
155
|
-
### `new AegisClient(config,
|
|
148
|
+
### `new AegisClient(config, keyRing, currentKeyVersion, bidxKey?)`
|
|
156
149
|
|
|
157
|
-
*
|
|
158
|
-
*
|
|
159
|
-
*
|
|
160
|
-
*
|
|
161
|
-
*
|
|
162
|
-
*
|
|
163
|
-
*
|
|
150
|
+
* **`config`** — `AegisConfig` object:
|
|
151
|
+
* **`adapter`**: any `DatabaseAdapter` (`SupabaseAdapter`, `MongoDBAdapter`, or custom)
|
|
152
|
+
* **`primaryKeyField`**: `string` (The ID field used for cryptographic contextual binding)
|
|
153
|
+
* **`encryptedFields`**: `Record<tableName, fieldName[]>`
|
|
154
|
+
* **`bidxFields`**: *(Optional)* `Record<tableName, fieldName[]>`
|
|
155
|
+
* **`keyRing`** — `Record<string, CryptoKey>` (A dictionary of all active and historical keys).
|
|
156
|
+
* **`currentKeyVersion`** — `string` (The version tag of the key to use for *new* encryptions).
|
|
157
|
+
* **`bidxKey`** — *(Optional)* `CryptoKey` from `generateBidxKey()` or `importKey()`
|
|
164
158
|
|
|
165
159
|
### `AegisClient` Methods
|
|
166
160
|
|
|
167
|
-
*
|
|
168
|
-
*
|
|
169
|
-
*
|
|
170
|
-
*
|
|
171
|
-
*
|
|
161
|
+
* **`insert(table, data)`**: Encrypts data and creates blind indexes before saving.
|
|
162
|
+
* **`select(table, query)`**: Fetches and automatically decrypts data. Intercepts blind index queries.
|
|
163
|
+
* **`update(table, data)`**: Re-encrypts modified fields with new IVs and updates blind indexes.
|
|
164
|
+
* **`delete(table, query)`**: Intercepts queries to securely delete by blind-indexed fields.
|
|
165
|
+
* **`selectRaw(table, query)`**: Bypasses decryption to return raw database records (useful for auditing or migrations).
|
|
172
166
|
|
|
173
167
|
### Adapters
|
|
174
168
|
|
|
@@ -184,14 +178,13 @@ class MyAdapter implements DatabaseAdapter {
|
|
|
184
178
|
|
|
185
179
|
## How It Works (Security Architecture)
|
|
186
180
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
* **
|
|
190
|
-
* **Field-Level IVs:** Every single encrypted field gets a unique, mathematically random Initialization Vector (IV) stored as a composite string (`iv:ciphertext`) to prevent keystream reuse attacks.
|
|
181
|
+
* **Web Crypto API (AES-256-GCM):** Runs natively in any modern browser or edge runtime without bloated dependencies.
|
|
182
|
+
* **Seamless Key Rotation:** Aegis-Lock accepts a dictionary of keys. It tags every database payload with the active key's version string. If a key is compromised, you simply introduce a `v2` key. New data is secured with `v2`, while historical data seamlessly decrypts using `v1` without a single second of database downtime.
|
|
183
|
+
* **Field-Level IVs:** Every single encrypted field gets a unique, mathematically random Initialization Vector (IV). The final database payload is formatted as `version:iv:ciphertext` to prevent keystream reuse attacks.
|
|
191
184
|
* **Contextual Binding (AAD):** Ciphertexts are cryptographically bound to the row's `primaryKeyField`. If an attacker copies an encrypted SSN from User A and pastes it into User B's row, the decryption will strictly fail.
|
|
192
185
|
* **Blind Indexing (HMAC-SHA256):** Because AES-GCM is non-deterministic (the same text encrypts differently every time), you cannot query standard encrypted fields. If configured via `bidxFields`, Aegis-Lock automatically generates deterministic, memory-aligned HMAC hashes. This allows you to search for exact matches (like looking up an email address) without exposing the plaintext to the database.
|
|
193
|
-
* **Database-
|
|
186
|
+
* **Database-Agnostic:** Swap adapters without changing your core application code.
|
|
194
187
|
|
|
195
188
|
## License
|
|
196
189
|
|
|
197
|
-
MIT
|
|
190
|
+
MIT
|
package/dist/client.d.ts
CHANGED
|
@@ -1,29 +1,29 @@
|
|
|
1
1
|
import type { DatabaseAdapter, AegisConfig } from "./types";
|
|
2
2
|
/**
|
|
3
3
|
* The primary client for aegis-lock.
|
|
4
|
-
* Handles automatic encryption, decryption, contextual binding,
|
|
5
|
-
* before interacting with the underlying database adapter.
|
|
4
|
+
* Handles automatic encryption, decryption, contextual binding, blind indexing,
|
|
5
|
+
* and Key Rotation before interacting with the underlying database adapter.
|
|
6
6
|
*/
|
|
7
7
|
export declare class AegisClient {
|
|
8
8
|
private adapter;
|
|
9
|
-
private
|
|
9
|
+
private keyRing;
|
|
10
|
+
private currentKeyVersion;
|
|
10
11
|
private bidxKey?;
|
|
11
12
|
private encryptedFields;
|
|
12
13
|
private bidxFields;
|
|
13
14
|
private primaryKeyField;
|
|
14
15
|
/**
|
|
15
|
-
* Initializes the AegisClient.
|
|
16
|
-
*
|
|
17
|
-
* @param
|
|
16
|
+
* Initializes the AegisClient with Key Rotation support.
|
|
17
|
+
*
|
|
18
|
+
* @param config - Configuration including the database adapter, primary key field, and field rules.
|
|
19
|
+
* @param keyRing - A dictionary of historical and active CryptoKeys (e.g., { v1: key1, v2: key2 }).
|
|
20
|
+
* @param currentKeyVersion - The string identifier of the key to use for NEW encryptions (e.g., "v2").
|
|
18
21
|
* @param bidxKey - (Optional) The CryptoKey used for generating HMAC-SHA256 blind indexes.
|
|
19
22
|
*/
|
|
20
|
-
constructor(config: AegisConfig,
|
|
23
|
+
constructor(config: AegisConfig, keyRing: Record<string, CryptoKey>, currentKeyVersion: string, bidxKey?: CryptoKey);
|
|
21
24
|
/**
|
|
22
25
|
* Securely inserts a new record into the database.
|
|
23
|
-
* Automatically generates blind indexes and encrypts configured fields.
|
|
24
|
-
* * @param table - The database table or collection name.
|
|
25
|
-
* @param data - The plaintext data object to insert. Must include the primary key.
|
|
26
|
-
* @returns The inserted data (as stored in the database) or an error.
|
|
26
|
+
* Automatically generates blind indexes and encrypts configured fields using the CURRENT key version.
|
|
27
27
|
*/
|
|
28
28
|
insert(table: string, data: Record<string, unknown>): Promise<{
|
|
29
29
|
data: Record<string, unknown>[] | null;
|
|
@@ -31,10 +31,7 @@ export declare class AegisClient {
|
|
|
31
31
|
}>;
|
|
32
32
|
/**
|
|
33
33
|
* Retrieves and automatically decrypts records from the database.
|
|
34
|
-
*
|
|
35
|
-
* * @param table - The database table or collection name.
|
|
36
|
-
* @param query - The column and value to search for (e.g., { column: "email", value: "alice@example.com" }).
|
|
37
|
-
* @returns The decrypted plaintext data or an error.
|
|
34
|
+
* Dynamically selects the correct decryption key based on the payload's version tag.
|
|
38
35
|
*/
|
|
39
36
|
select(table: string, query?: {
|
|
40
37
|
column?: string;
|
|
@@ -46,22 +43,12 @@ export declare class AegisClient {
|
|
|
46
43
|
}>;
|
|
47
44
|
/**
|
|
48
45
|
* Securely modifies an existing record.
|
|
49
|
-
* Re-encrypts data with a new unique IV and
|
|
50
|
-
* * @param table - The database table or collection name.
|
|
51
|
-
* @param data - The updated plaintext data. Must include the primary key.
|
|
52
|
-
* @returns The updated data (as stored in the database) or an error.
|
|
46
|
+
* Re-encrypts data with a new unique IV and the CURRENT key version.
|
|
53
47
|
*/
|
|
54
48
|
update(table: string, data: Record<string, unknown>): Promise<{
|
|
55
49
|
data: any[] | null;
|
|
56
50
|
error: any;
|
|
57
51
|
}>;
|
|
58
|
-
/**
|
|
59
|
-
* Securely removes records from the database.
|
|
60
|
-
* Automatically hashes the search query if deleting by a blind-indexed field.
|
|
61
|
-
* * @param table - The database table or collection name.
|
|
62
|
-
* @param query - The column and value to identify the record to delete.
|
|
63
|
-
* @returns The result of the deletion operation or an error.
|
|
64
|
-
*/
|
|
65
52
|
delete(table: string, query: {
|
|
66
53
|
column: string;
|
|
67
54
|
value: unknown;
|
|
@@ -69,13 +56,6 @@ export declare class AegisClient {
|
|
|
69
56
|
data: any[] | null;
|
|
70
57
|
error: any;
|
|
71
58
|
}>;
|
|
72
|
-
/**
|
|
73
|
-
* Bypasses decryption and retrieves the raw, encrypted data directly from the database.
|
|
74
|
-
* Useful for database migrations, auditing, or debugging.
|
|
75
|
-
* * @param table - The database table or collection name.
|
|
76
|
-
* @param query - The raw query to execute against the database.
|
|
77
|
-
* @returns The raw, encrypted database rows.
|
|
78
|
-
*/
|
|
79
59
|
selectRaw(table: string, query?: {
|
|
80
60
|
column?: string;
|
|
81
61
|
value?: unknown;
|
|
@@ -84,10 +64,6 @@ export declare class AegisClient {
|
|
|
84
64
|
data: Record<string, unknown>[] | null;
|
|
85
65
|
error: unknown;
|
|
86
66
|
}>;
|
|
87
|
-
/**
|
|
88
|
-
* Gets the underlying database adapter instance.
|
|
89
|
-
* Useful for executing custom database commands outside of Aegis's encryption flow.
|
|
90
|
-
*/
|
|
91
67
|
get db(): DatabaseAdapter;
|
|
92
68
|
}
|
|
93
69
|
//# sourceMappingURL=client.d.ts.map
|
package/dist/client.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAG5D;;;;GAIG;AACH,qBAAa,WAAW;IACtB,OAAO,CAAC,OAAO,CAAkB;IACjC,OAAO,CAAC,
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAG5D;;;;GAIG;AACH,qBAAa,WAAW;IACtB,OAAO,CAAC,OAAO,CAAkB;IACjC,OAAO,CAAC,OAAO,CAA4B;IAC3C,OAAO,CAAC,iBAAiB,CAAS;IAClC,OAAO,CAAC,OAAO,CAAC,CAAY;IAC5B,OAAO,CAAC,eAAe,CAA2B;IAClD,OAAO,CAAC,UAAU,CAA2B;IAC7C,OAAO,CAAC,eAAe,CAAS;IAEhC;;;;;;;OAOG;gBAED,MAAM,EAAE,WAAW,EACnB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,EAClC,iBAAiB,EAAE,MAAM,EACzB,OAAO,CAAC,EAAE,SAAS;IAWrB;;;OAGG;IACG,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;;;;IA6CzD;;;OAGG;IACG,MAAM,CACV,KAAK,EAAE,MAAM,EACb,KAAK,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE;;;;IAgE9D;;;OAGG;IACG,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;;;;IAsCnD,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,OAAO,CAAA;KAAE;;;;IAgB/D,SAAS,CACb,KAAK,EAAE,MAAM,EACb,KAAK,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE;;;;IAK9D,IAAI,EAAE,IAAI,eAAe,CAExB;CACF"}
|
package/dist/client.js
CHANGED
|
@@ -1,30 +1,30 @@
|
|
|
1
1
|
import { encrypt, decrypt, generateBlindIndex } from "./crypto";
|
|
2
2
|
/**
|
|
3
3
|
* The primary client for aegis-lock.
|
|
4
|
-
* Handles automatic encryption, decryption, contextual binding,
|
|
5
|
-
* before interacting with the underlying database adapter.
|
|
4
|
+
* Handles automatic encryption, decryption, contextual binding, blind indexing,
|
|
5
|
+
* and Key Rotation before interacting with the underlying database adapter.
|
|
6
6
|
*/
|
|
7
7
|
export class AegisClient {
|
|
8
8
|
/**
|
|
9
|
-
* Initializes the AegisClient.
|
|
10
|
-
*
|
|
11
|
-
* @param
|
|
9
|
+
* Initializes the AegisClient with Key Rotation support.
|
|
10
|
+
*
|
|
11
|
+
* @param config - Configuration including the database adapter, primary key field, and field rules.
|
|
12
|
+
* @param keyRing - A dictionary of historical and active CryptoKeys (e.g., { v1: key1, v2: key2 }).
|
|
13
|
+
* @param currentKeyVersion - The string identifier of the key to use for NEW encryptions (e.g., "v2").
|
|
12
14
|
* @param bidxKey - (Optional) The CryptoKey used for generating HMAC-SHA256 blind indexes.
|
|
13
15
|
*/
|
|
14
|
-
constructor(config,
|
|
16
|
+
constructor(config, keyRing, currentKeyVersion, bidxKey) {
|
|
15
17
|
this.adapter = config.adapter;
|
|
16
|
-
this.
|
|
17
|
-
this.
|
|
18
|
+
this.keyRing = keyRing;
|
|
19
|
+
this.currentKeyVersion = currentKeyVersion;
|
|
20
|
+
this.bidxKey = bidxKey;
|
|
18
21
|
this.encryptedFields = config.encryptedFields;
|
|
19
22
|
this.bidxFields = config.bidxFields || {};
|
|
20
23
|
this.primaryKeyField = config.primaryKeyField;
|
|
21
24
|
}
|
|
22
25
|
/**
|
|
23
26
|
* Securely inserts a new record into the database.
|
|
24
|
-
* Automatically generates blind indexes and encrypts configured fields.
|
|
25
|
-
* * @param table - The database table or collection name.
|
|
26
|
-
* @param data - The plaintext data object to insert. Must include the primary key.
|
|
27
|
-
* @returns The inserted data (as stored in the database) or an error.
|
|
27
|
+
* Automatically generates blind indexes and encrypts configured fields using the CURRENT key version.
|
|
28
28
|
*/
|
|
29
29
|
async insert(table, data) {
|
|
30
30
|
const fields = this.encryptedFields[table] || [];
|
|
@@ -36,18 +36,20 @@ export class AegisClient {
|
|
|
36
36
|
throw new Error(`Aegis: Cannot encrypt. Missing primary key '${this.primaryKeyField}' in payload.`);
|
|
37
37
|
}
|
|
38
38
|
const aadContext = String(rowId);
|
|
39
|
-
|
|
39
|
+
const activeKey = this.keyRing[this.currentKeyVersion]; // Grab the active key
|
|
40
|
+
// 1. Handle Blind Indexing FIRST
|
|
40
41
|
for (const field of bidxFields) {
|
|
41
42
|
if (row[field] != null && this.bidxKey) {
|
|
42
|
-
row[`${field}_bidx`] = await generateBlindIndex(String(row[field]),
|
|
43
|
-
this.bidxKey);
|
|
43
|
+
row[`${field}_bidx`] = await generateBlindIndex(String(row[field]), this.bidxKey);
|
|
44
44
|
}
|
|
45
45
|
}
|
|
46
|
-
// 2. Handle Encryption SECOND
|
|
46
|
+
// 2. Handle Encryption SECOND
|
|
47
47
|
for (const field of fields) {
|
|
48
48
|
if (row[field] != null) {
|
|
49
|
-
|
|
50
|
-
row[field]
|
|
49
|
+
// Pass the active key and the version tag to the new encrypt function
|
|
50
|
+
const { version, ciphertext, iv } = await encrypt(String(row[field]), activeKey, this.currentKeyVersion, aadContext);
|
|
51
|
+
// Store it in the DB as "version:iv:ciphertext"
|
|
52
|
+
row[field] = `${version}:${iv}:${ciphertext}`;
|
|
51
53
|
}
|
|
52
54
|
}
|
|
53
55
|
}
|
|
@@ -55,17 +57,11 @@ export class AegisClient {
|
|
|
55
57
|
}
|
|
56
58
|
/**
|
|
57
59
|
* Retrieves and automatically decrypts records from the database.
|
|
58
|
-
*
|
|
59
|
-
* * @param table - The database table or collection name.
|
|
60
|
-
* @param query - The column and value to search for (e.g., { column: "email", value: "alice@example.com" }).
|
|
61
|
-
* @returns The decrypted plaintext data or an error.
|
|
60
|
+
* Dynamically selects the correct decryption key based on the payload's version tag.
|
|
62
61
|
*/
|
|
63
62
|
async select(table, query) {
|
|
64
|
-
// Intercept and swap query for Blind Indexing (NEW)
|
|
65
63
|
const bidxFields = this.bidxFields[table] || [];
|
|
66
64
|
let activeQuery = query;
|
|
67
|
-
// Make sure this uses THIS.bidxKey
|
|
68
|
-
// Inside your select method in client.ts
|
|
69
65
|
if (query?.column &&
|
|
70
66
|
query?.value &&
|
|
71
67
|
bidxFields.includes(query.column) &&
|
|
@@ -74,7 +70,7 @@ export class AegisClient {
|
|
|
74
70
|
activeQuery = {
|
|
75
71
|
...query,
|
|
76
72
|
column: `${query.column}_bidx`,
|
|
77
|
-
value: blindIndexValue,
|
|
73
|
+
value: blindIndexValue,
|
|
78
74
|
};
|
|
79
75
|
}
|
|
80
76
|
const { data, error } = await this.adapter.select(table, activeQuery);
|
|
@@ -90,14 +86,19 @@ export class AegisClient {
|
|
|
90
86
|
return decRow;
|
|
91
87
|
const aadContext = String(rowId);
|
|
92
88
|
for (const field of fields) {
|
|
93
|
-
const
|
|
94
|
-
if (typeof
|
|
95
|
-
const
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
89
|
+
const payloadStr = decRow[field];
|
|
90
|
+
if (typeof payloadStr === "string" && payloadStr.includes(":")) {
|
|
91
|
+
const parts = payloadStr.split(":");
|
|
92
|
+
// Check for our new 3-part versioned payload
|
|
93
|
+
if (parts.length === 3) {
|
|
94
|
+
const [version, iv, ciphertext] = parts;
|
|
95
|
+
try {
|
|
96
|
+
// Pass the whole KeyRing. crypto.ts will pick the right one.
|
|
97
|
+
decRow[field] = await decrypt({ version, ciphertext, iv }, this.keyRing, aadContext);
|
|
98
|
+
}
|
|
99
|
+
catch {
|
|
100
|
+
// Tampering detected or wrong key
|
|
101
|
+
}
|
|
101
102
|
}
|
|
102
103
|
}
|
|
103
104
|
}
|
|
@@ -107,10 +108,7 @@ export class AegisClient {
|
|
|
107
108
|
}
|
|
108
109
|
/**
|
|
109
110
|
* Securely modifies an existing record.
|
|
110
|
-
* Re-encrypts data with a new unique IV and
|
|
111
|
-
* * @param table - The database table or collection name.
|
|
112
|
-
* @param data - The updated plaintext data. Must include the primary key.
|
|
113
|
-
* @returns The updated data (as stored in the database) or an error.
|
|
111
|
+
* Re-encrypts data with a new unique IV and the CURRENT key version.
|
|
114
112
|
*/
|
|
115
113
|
async update(table, data) {
|
|
116
114
|
const fields = this.encryptedFields[table] || [];
|
|
@@ -121,35 +119,25 @@ export class AegisClient {
|
|
|
121
119
|
throw new Error(`Aegis: Cannot update. Missing primary key '${this.primaryKeyField}' in payload.`);
|
|
122
120
|
}
|
|
123
121
|
const aadContext = String(rowId);
|
|
122
|
+
const activeKey = this.keyRing[this.currentKeyVersion];
|
|
124
123
|
if (fields.length > 0 || bidxFields.length > 0) {
|
|
125
|
-
// 1. Update Blind Indexes
|
|
126
124
|
for (const field of bidxFields) {
|
|
127
125
|
if (row[field] != null && this.bidxKey) {
|
|
128
126
|
row[`${field}_bidx`] = await generateBlindIndex(String(row[field]), this.bidxKey);
|
|
129
127
|
}
|
|
130
128
|
}
|
|
131
|
-
// 2. Encrypt updated fields with a brand new IV
|
|
132
129
|
for (const field of fields) {
|
|
133
130
|
if (row[field] != null) {
|
|
134
|
-
const { ciphertext, iv } = await encrypt(String(row[field]), this.
|
|
135
|
-
row[field] = `${iv}:${ciphertext}`;
|
|
131
|
+
const { version, ciphertext, iv } = await encrypt(String(row[field]), activeKey, this.currentKeyVersion, aadContext);
|
|
132
|
+
row[field] = `${version}:${iv}:${ciphertext}`;
|
|
136
133
|
}
|
|
137
134
|
}
|
|
138
135
|
}
|
|
139
136
|
return this.adapter.update(table, row);
|
|
140
137
|
}
|
|
141
|
-
/**
|
|
142
|
-
* Securely removes records from the database.
|
|
143
|
-
* Automatically hashes the search query if deleting by a blind-indexed field.
|
|
144
|
-
* * @param table - The database table or collection name.
|
|
145
|
-
* @param query - The column and value to identify the record to delete.
|
|
146
|
-
* @returns The result of the deletion operation or an error.
|
|
147
|
-
*/
|
|
148
138
|
async delete(table, query) {
|
|
149
139
|
const bidxFields = this.bidxFields[table] || [];
|
|
150
140
|
let activeQuery = query;
|
|
151
|
-
// Intercept the query! If they are deleting by an encrypted field (like email),
|
|
152
|
-
// we must hash the value so the database knows which row to delete.
|
|
153
141
|
if (bidxFields.includes(query.column) && this.bidxKey) {
|
|
154
142
|
const blindIndexValue = await generateBlindIndex(String(query.value), this.bidxKey);
|
|
155
143
|
activeQuery = {
|
|
@@ -160,20 +148,9 @@ export class AegisClient {
|
|
|
160
148
|
}
|
|
161
149
|
return this.adapter.delete(table, activeQuery);
|
|
162
150
|
}
|
|
163
|
-
/**
|
|
164
|
-
* Bypasses decryption and retrieves the raw, encrypted data directly from the database.
|
|
165
|
-
* Useful for database migrations, auditing, or debugging.
|
|
166
|
-
* * @param table - The database table or collection name.
|
|
167
|
-
* @param query - The raw query to execute against the database.
|
|
168
|
-
* @returns The raw, encrypted database rows.
|
|
169
|
-
*/
|
|
170
151
|
async selectRaw(table, query) {
|
|
171
152
|
return this.adapter.select(table, query);
|
|
172
153
|
}
|
|
173
|
-
/**
|
|
174
|
-
* Gets the underlying database adapter instance.
|
|
175
|
-
* Useful for executing custom database commands outside of Aegis's encryption flow.
|
|
176
|
-
*/
|
|
177
154
|
get db() {
|
|
178
155
|
return this.adapter;
|
|
179
156
|
}
|
package/dist/client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","sourceRoot":"","sources":["../client.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AAEhE;;;;GAIG;AACH,MAAM,OAAO,WAAW;
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../client.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AAEhE;;;;GAIG;AACH,MAAM,OAAO,WAAW;IAStB;;;;;;;OAOG;IACH,YACE,MAAmB,EACnB,OAAkC,EAClC,iBAAyB,EACzB,OAAmB;QAEnB,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC;QAC9B,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,iBAAiB,GAAG,iBAAiB,CAAC;QAC3C,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,eAAe,GAAG,MAAM,CAAC,eAAe,CAAC;QAC9C,IAAI,CAAC,UAAU,GAAG,MAAM,CAAC,UAAU,IAAI,EAAE,CAAC;QAC1C,IAAI,CAAC,eAAe,GAAG,MAAM,CAAC,eAAe,CAAC;IAChD,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,MAAM,CAAC,KAAa,EAAE,IAA6B;QACvD,MAAM,MAAM,GAAG,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;QACjD,MAAM,UAAU,GAAG,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;QAChD,MAAM,GAAG,GAA4B,EAAE,GAAG,IAAI,EAAE,CAAC;QAEjD,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC/C,MAAM,KAAK,GAAG,GAAG,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;YACxC,IAAI,CAAC,KAAK,EAAE,CAAC;gBACX,MAAM,IAAI,KAAK,CACb,+CAA+C,IAAI,CAAC,eAAe,eAAe,CACnF,CAAC;YACJ,CAAC;YAED,MAAM,UAAU,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;YACjC,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC,CAAC,sBAAsB;YAE9E,iCAAiC;YACjC,KAAK,MAAM,KAAK,IAAI,UAAU,EAAE,CAAC;gBAC/B,IAAI,GAAG,CAAC,KAAK,CAAC,IAAI,IAAI,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;oBACvC,GAAG,CAAC,GAAG,KAAK,OAAO,CAAC,GAAG,MAAM,kBAAkB,CAC7C,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,EAClB,IAAI,CAAC,OAAO,CACb,CAAC;gBACJ,CAAC;YACH,CAAC;YAED,8BAA8B;YAC9B,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;gBAC3B,IAAI,GAAG,CAAC,KAAK,CAAC,IAAI,IAAI,EAAE,CAAC;oBACvB,sEAAsE;oBACtE,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,EAAE,EAAE,GAAG,MAAM,OAAO,CAC/C,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,EAClB,SAAS,EACT,IAAI,CAAC,iBAAiB,EACtB,UAAU,CACX,CAAC;oBACF,gDAAgD;oBAChD,GAAG,CAAC,KAAK,CAAC,GAAG,GAAG,OAAO,IAAI,EAAE,IAAI,UAAU,EAAE,CAAC;gBAChD,CAAC;YACH,CAAC;QACH,CAAC;QAED,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;IACzC,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,MAAM,CACV,KAAa,EACb,KAA4D;QAE5D,MAAM,UAAU,GAAG,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;QAChD,IAAI,WAAW,GAAG,KAAK,CAAC;QAExB,IACE,KAAK,EAAE,MAAM;YACb,KAAK,EAAE,KAAK;YACZ,UAAU,CAAC,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC;YACjC,IAAI,CAAC,OAAO,EACZ,CAAC;YACD,MAAM,eAAe,GAAG,MAAM,kBAAkB,CAC9C,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,EACnB,IAAI,CAAC,OAAO,CACb,CAAC;YACF,WAAW,GAAG;gBACZ,GAAG,KAAK;gBACR,MAAM,EAAE,GAAG,KAAK,CAAC,MAAM,OAAO;gBAC9B,KAAK,EAAE,eAAe;aACvB,CAAC;QACJ,CAAC;QAED,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,EAAE,WAAW,CAAC,CAAC;QACtE,IAAI,KAAK,IAAI,CAAC,IAAI;YAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;QAE3C,MAAM,MAAM,GAAG,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;QACjD,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;QAEhD,MAAM,SAAS,GAAG,MAAM,OAAO,CAAC,GAAG,CACjC,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,GAA4B,EAAE,EAAE;YAC9C,MAAM,MAAM,GAAG,EAAE,GAAG,GAAG,EAAE,CAAC;YAC1B,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;YAE3C,IAAI,CAAC,KAAK;gBAAE,OAAO,MAAM,CAAC;YAC1B,MAAM,UAAU,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;YAEjC,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;gBAC3B,MAAM,UAAU,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;gBACjC,IAAI,OAAO,UAAU,KAAK,QAAQ,IAAI,UAAU,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;oBAC/D,MAAM,KAAK,GAAG,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;oBAEpC,6CAA6C;oBAC7C,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;wBACvB,MAAM,CAAC,OAAO,EAAE,EAAE,EAAE,UAAU,CAAC,GAAG,KAAK,CAAC;wBACxC,IAAI,CAAC;4BACH,6DAA6D;4BAC7D,MAAM,CAAC,KAAK,CAAC,GAAG,MAAM,OAAO,CAC3B,EAAE,OAAO,EAAE,UAAU,EAAE,EAAE,EAAE,EAC3B,IAAI,CAAC,OAAO,EACZ,UAAU,CACX,CAAC;wBACJ,CAAC;wBAAC,MAAM,CAAC;4BACP,kCAAkC;wBACpC,CAAC;oBACH,CAAC;gBACH,CAAC;YACH,CAAC;YACD,OAAO,MAAM,CAAC;QAChB,CAAC,CAAC,CACH,CAAC;QAEF,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;IACpC,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,MAAM,CAAC,KAAa,EAAE,IAA6B;QACvD,MAAM,MAAM,GAAG,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;QACjD,MAAM,UAAU,GAAG,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;QAChD,MAAM,GAAG,GAA4B,EAAE,GAAG,IAAI,EAAE,CAAC;QAEjD,MAAM,KAAK,GAAG,GAAG,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;QACxC,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,MAAM,IAAI,KAAK,CACb,8CAA8C,IAAI,CAAC,eAAe,eAAe,CAClF,CAAC;QACJ,CAAC;QAED,MAAM,UAAU,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;QACjC,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;QAEvD,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC/C,KAAK,MAAM,KAAK,IAAI,UAAU,EAAE,CAAC;gBAC/B,IAAI,GAAG,CAAC,KAAK,CAAC,IAAI,IAAI,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;oBACvC,GAAG,CAAC,GAAG,KAAK,OAAO,CAAC,GAAG,MAAM,kBAAkB,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;gBACpF,CAAC;YACH,CAAC;YAED,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;gBAC3B,IAAI,GAAG,CAAC,KAAK,CAAC,IAAI,IAAI,EAAE,CAAC;oBACvB,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,EAAE,EAAE,GAAG,MAAM,OAAO,CAC/C,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,EAClB,SAAS,EACT,IAAI,CAAC,iBAAiB,EACtB,UAAU,CACX,CAAC;oBACF,GAAG,CAAC,KAAK,CAAC,GAAG,GAAG,OAAO,IAAI,EAAE,IAAI,UAAU,EAAE,CAAC;gBAChD,CAAC;YACH,CAAC;QACH,CAAC;QAED,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;IACzC,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,KAAa,EAAE,KAAyC;QACnE,MAAM,UAAU,GAAG,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;QAChD,IAAI,WAAW,GAAG,KAAK,CAAC;QAExB,IAAI,UAAU,CAAC,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACtD,MAAM,eAAe,GAAG,MAAM,kBAAkB,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;YACpF,WAAW,GAAG;gBACZ,GAAG,KAAK;gBACR,MAAM,EAAE,GAAG,KAAK,CAAC,MAAM,OAAO;gBAC9B,KAAK,EAAE,eAAe;aACvB,CAAC;QACJ,CAAC;QAED,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,EAAE,WAAW,CAAC,CAAC;IACjD,CAAC;IAED,KAAK,CAAC,SAAS,CACb,KAAa,EACb,KAA4D;QAE5D,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;IAC3C,CAAC;IAED,IAAI,EAAE;QACJ,OAAO,IAAI,CAAC,OAAO,CAAC;IACtB,CAAC;CACF"}
|
package/dist/crypto.d.ts
CHANGED
|
@@ -21,22 +21,25 @@ export declare function importKey(base64: string): Promise<CryptoKey>;
|
|
|
21
21
|
* Encrypts a plaintext string using AES-256-GCM.
|
|
22
22
|
* Automatically generates a unique 12-byte Initialization Vector (IV) and applies
|
|
23
23
|
* Contextual Binding (AAD) to tie the ciphertext to a specific database row.
|
|
24
|
-
*
|
|
24
|
+
* @param plaintext - The sensitive data to encrypt.
|
|
25
25
|
* @param key - The master AES-GCM CryptoKey.
|
|
26
|
+
* @param keyVersion - The string identifier for the active key (e.g., "v2").
|
|
26
27
|
* @param aadContext - The row ID or primary key to bind this ciphertext to.
|
|
27
28
|
* @returns A Promise resolving to an object containing the Base64 `ciphertext` and `iv`.
|
|
28
29
|
*/
|
|
29
|
-
export declare function encrypt(plaintext: string, key: CryptoKey, aadContext: string): Promise<EncryptedPayload>;
|
|
30
|
+
export declare function encrypt(plaintext: string, key: CryptoKey, keyVersion: string, aadContext: string): Promise<EncryptedPayload>;
|
|
30
31
|
/**
|
|
31
32
|
* Decrypts an AES-256-GCM payload back into plaintext.
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
* @param
|
|
33
|
+
* Supports Key Rotation by reading the payload's version and selecting the correct key.
|
|
34
|
+
* Strictly verifies the Context (AAD) to ensure data integrity.
|
|
35
|
+
*
|
|
36
|
+
* @param payload - The EncryptedPayload containing `version`, `ciphertext`, and `iv`.
|
|
37
|
+
* @param keyRing - A dictionary of historical and active CryptoKeys (e.g., { "v1": key1, "v2": key2 }).
|
|
36
38
|
* @param aadContext - The row ID or primary key that this ciphertext is bound to.
|
|
37
39
|
* @returns A Promise resolving to the decrypted plaintext string.
|
|
38
40
|
*/
|
|
39
|
-
export declare function decrypt(payload: EncryptedPayload,
|
|
41
|
+
export declare function decrypt(payload: EncryptedPayload, keyRing: Record<string, CryptoKey>, // Accepts multiple keys
|
|
42
|
+
aadContext: string): Promise<string>;
|
|
40
43
|
/** * Generates a dedicated HMAC-SHA256 key for deterministic Blind Indexing.
|
|
41
44
|
* This key should be kept separate from the master encryption key.
|
|
42
45
|
* * @returns A Promise resolving to an HMAC CryptoKey.
|
package/dist/crypto.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"crypto.d.ts","sourceRoot":"","sources":["../crypto.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAqC3C;;;GAGG;AACH,wBAAsB,WAAW,IAAI,OAAO,CAAC,SAAS,CAAC,CAKtD;AAED;;;;;GAKG;AACH,wBAAsB,SAAS,CAAC,GAAG,EAAE,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC,CAG/D;AAED;;;;GAIG;AACH,wBAAsB,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC,CASlE;AAED
|
|
1
|
+
{"version":3,"file":"crypto.d.ts","sourceRoot":"","sources":["../crypto.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAqC3C;;;GAGG;AACH,wBAAsB,WAAW,IAAI,OAAO,CAAC,SAAS,CAAC,CAKtD;AAED;;;;;GAKG;AACH,wBAAsB,SAAS,CAAC,GAAG,EAAE,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC,CAG/D;AAED;;;;GAIG;AACH,wBAAsB,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC,CASlE;AAED;;;;;;;;;GASG;AACH,wBAAsB,OAAO,CAC3B,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,SAAS,EACd,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,gBAAgB,CAAC,CAsB3B;AAED;;;;;;;;;GASG;AACH,wBAAsB,OAAO,CAC3B,OAAO,EAAE,gBAAgB,EACzB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,EAAE,wBAAwB;AAC5D,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,MAAM,CAAC,CA6BjB;AAID;;;GAGG;AACH,wBAAsB,eAAe,IAAI,OAAO,CAAC,SAAS,CAAC,CAK1D;AAED;;;;;;GAMG;AACH,wBAAsB,kBAAkB,CACtC,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,SAAS,GACb,OAAO,CAAC,MAAM,CAAC,CAkBjB"}
|
package/dist/crypto.js
CHANGED
|
@@ -63,12 +63,13 @@ export async function importKey(base64) {
|
|
|
63
63
|
* Encrypts a plaintext string using AES-256-GCM.
|
|
64
64
|
* Automatically generates a unique 12-byte Initialization Vector (IV) and applies
|
|
65
65
|
* Contextual Binding (AAD) to tie the ciphertext to a specific database row.
|
|
66
|
-
*
|
|
66
|
+
* @param plaintext - The sensitive data to encrypt.
|
|
67
67
|
* @param key - The master AES-GCM CryptoKey.
|
|
68
|
+
* @param keyVersion - The string identifier for the active key (e.g., "v2").
|
|
68
69
|
* @param aadContext - The row ID or primary key to bind this ciphertext to.
|
|
69
70
|
* @returns A Promise resolving to an object containing the Base64 `ciphertext` and `iv`.
|
|
70
71
|
*/
|
|
71
|
-
export async function encrypt(plaintext, key, aadContext) {
|
|
72
|
+
export async function encrypt(plaintext, key, keyVersion, aadContext) {
|
|
72
73
|
const iv = crypto.getRandomValues(new Uint8Array(12)); // ALWAYS unique
|
|
73
74
|
const encoded = new TextEncoder().encode(plaintext);
|
|
74
75
|
const algorithm = {
|
|
@@ -79,18 +80,25 @@ export async function encrypt(plaintext, key, aadContext) {
|
|
|
79
80
|
algorithm.additionalData = new TextEncoder().encode(aadContext);
|
|
80
81
|
}
|
|
81
82
|
const cipherBuffer = await crypto.subtle.encrypt(algorithm, key, encoded);
|
|
82
|
-
return { ciphertext: bufferToBase64(cipherBuffer), iv: bufferToBase64(iv) };
|
|
83
|
+
return { version: keyVersion, ciphertext: bufferToBase64(cipherBuffer), iv: bufferToBase64(iv) };
|
|
83
84
|
}
|
|
84
85
|
/**
|
|
85
86
|
* Decrypts an AES-256-GCM payload back into plaintext.
|
|
86
|
-
*
|
|
87
|
-
*
|
|
88
|
-
*
|
|
89
|
-
* @param
|
|
87
|
+
* Supports Key Rotation by reading the payload's version and selecting the correct key.
|
|
88
|
+
* Strictly verifies the Context (AAD) to ensure data integrity.
|
|
89
|
+
*
|
|
90
|
+
* @param payload - The EncryptedPayload containing `version`, `ciphertext`, and `iv`.
|
|
91
|
+
* @param keyRing - A dictionary of historical and active CryptoKeys (e.g., { "v1": key1, "v2": key2 }).
|
|
90
92
|
* @param aadContext - The row ID or primary key that this ciphertext is bound to.
|
|
91
93
|
* @returns A Promise resolving to the decrypted plaintext string.
|
|
92
94
|
*/
|
|
93
|
-
export async function decrypt(payload,
|
|
95
|
+
export async function decrypt(payload, keyRing, // Accepts multiple keys
|
|
96
|
+
aadContext) {
|
|
97
|
+
// Identify which key to use based on the payload's version tag
|
|
98
|
+
const targetKey = keyRing[payload.version];
|
|
99
|
+
if (!targetKey) {
|
|
100
|
+
throw new Error(`CRITICAL: Key version [${payload.version}] not found in provided KeyRing.`);
|
|
101
|
+
}
|
|
94
102
|
const cipherBytes = base64ToBuffer(payload.ciphertext);
|
|
95
103
|
const iv = base64ToBuffer(payload.iv);
|
|
96
104
|
const algorithm = {
|
|
@@ -100,7 +108,8 @@ export async function decrypt(payload, key, aadContext) {
|
|
|
100
108
|
if (aadContext) {
|
|
101
109
|
algorithm.additionalData = new TextEncoder().encode(aadContext);
|
|
102
110
|
}
|
|
103
|
-
const decrypted = await crypto.subtle.decrypt(algorithm,
|
|
111
|
+
const decrypted = await crypto.subtle.decrypt(algorithm, targetKey, // Use the dynamically selected key
|
|
112
|
+
cipherBytes);
|
|
104
113
|
return new TextDecoder().decode(decrypted);
|
|
105
114
|
}
|
|
106
115
|
const HMAC_ALGO = "HMAC";
|
package/dist/crypto.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"crypto.js","sourceRoot":"","sources":["../crypto.ts"],"names":[],"mappings":"AAEA,MAAM,IAAI,GAAG,SAAS,CAAC;AACvB,MAAM,UAAU,GAAG,GAAG,CAAC;AAEvB;;;;;GAKG;AACH,SAAS,cAAc,CAAC,MAAgC;IACtD,IAAI,MAAM,GAAG,EAAE,CAAC;IAChB,iCAAiC;IACjC,MAAM,KAAK,GAAG,MAAM,YAAY,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,UAAU,CAAC,MAAM,CAAC,CAAC;IAC7E,MAAM,GAAG,GAAG,KAAK,CAAC,UAAU,CAAC;IAC7B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC;QAC7B,MAAM,IAAI,MAAM,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAC1C,CAAC;IACD,OAAO,IAAI,CAAC,MAAM,CAAC,CAAC;AACtB,CAAC;AAED;;;;;GAKG;AACH,SAAS,cAAc,CAAC,MAAc;IACpC,MAAM,YAAY,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC;IAClC,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC;IAClD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,YAAY,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAC7C,KAAK,CAAC,CAAC,CAAC,GAAG,YAAY,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;IACxC,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW;IAC/B,OAAO,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,EAAE,IAAI,EAAE;QACzE,SAAS;QACT,SAAS;KACV,CAAC,CAAC;AACL,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,GAAc;IAC5C,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;IACtD,OAAO,cAAc,CAAC,GAAG,CAAC,CAAC;AAC7B,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,MAAc;IAC5C,MAAM,GAAG,GAAG,cAAc,CAAC,MAAM,CAAC,CAAC;IACnC,OAAO,MAAM,CAAC,MAAM,CAAC,SAAS,CAC5B,KAAK,EACL,GAAmB,EACnB,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,EAClC,IAAI,EACJ,CAAC,SAAS,EAAE,SAAS,CAAC,CACvB,CAAC;AACJ,CAAC;AAED
|
|
1
|
+
{"version":3,"file":"crypto.js","sourceRoot":"","sources":["../crypto.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
CHANGED
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,eAAe;IAC9B,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,IAAI,CAAC;QAAC,KAAK,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;IAC1H,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,IAAI,CAAC;QAAC,KAAK,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;IACzJ,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC;QAAE,IAAI,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;QAAC,KAAK,EAAE,GAAG,CAAA;KAAE,CAAC,CAAC;IAClG,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,OAAO,CAAA;KAAE,GAAG,OAAO,CAAC;QAAE,IAAI,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;QAAC,KAAK,EAAE,GAAG,CAAA;KAAE,CAAC,CAAC;CAC/G;AAED,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,eAAe,CAAC;IACzB,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;IAC1C,eAAe,EAAE,MAAM,CAAC;IACxB,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;CACvC;AAED,MAAM,WAAW,gBAAgB;IAC/B,UAAU,EAAE,MAAM,CAAC;IACnB,EAAE,EAAE,MAAM,CAAC;CACZ;AAED,MAAM,WAAW,YAAY;IAC3B,GAAG,EAAE,SAAS,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;CAClB"}
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,eAAe;IAC9B,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,IAAI,CAAC;QAAC,KAAK,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;IAC1H,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,IAAI,CAAC;QAAC,KAAK,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;IACzJ,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC;QAAE,IAAI,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;QAAC,KAAK,EAAE,GAAG,CAAA;KAAE,CAAC,CAAC;IAClG,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,OAAO,CAAA;KAAE,GAAG,OAAO,CAAC;QAAE,IAAI,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;QAAC,KAAK,EAAE,GAAG,CAAA;KAAE,CAAC,CAAC;CAC/G;AAED,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,eAAe,CAAC;IACzB,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;IAC1C,eAAe,EAAE,MAAM,CAAC;IACxB,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;CACvC;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,EAAE,EAAE,MAAM,CAAC;CACZ;AAED,MAAM,WAAW,YAAY;IAC3B,GAAG,EAAE,SAAS,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;CAClB"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "aegis-lock",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.2.0",
|
|
4
4
|
"description": "Database-agnostic client-side AES-256-GCM field-level encryption. Works with Supabase, MongoDB, or any database via pluggable adapters.",
|
|
5
|
+
"repository": {
|
|
6
|
+
"type": "git",
|
|
7
|
+
"url": "git+https://github.com/hritesh-saha/aegis-lock.git"
|
|
8
|
+
},
|
|
9
|
+
"bugs": {
|
|
10
|
+
"url": "https://github.com/hritesh-saha/aegis-lock/issues"
|
|
11
|
+
},
|
|
12
|
+
"homepage": "https://github.com/hritesh-saha/aegis-lock#readme",
|
|
5
13
|
"type": "module",
|
|
6
14
|
"main": "dist/index.js",
|
|
7
15
|
"module": "dist/index.js",
|
|
@@ -50,6 +58,9 @@
|
|
|
50
58
|
"peerDependenciesMeta": {
|
|
51
59
|
"@supabase/supabase-js": {
|
|
52
60
|
"optional": true
|
|
61
|
+
},
|
|
62
|
+
"mongodb": {
|
|
63
|
+
"optional": true
|
|
53
64
|
}
|
|
54
65
|
},
|
|
55
66
|
"devDependencies": {
|
|
@@ -57,6 +68,7 @@
|
|
|
57
68
|
"@types/jest": "^30.0.0",
|
|
58
69
|
"@types/node": "^25.3.5",
|
|
59
70
|
"jest": "^30.2.0",
|
|
71
|
+
"mongodb": "^7.1.1",
|
|
60
72
|
"ts-jest": "^29.4.6",
|
|
61
73
|
"typescript": "^5.9.3"
|
|
62
74
|
}
|