@immahq/aegis 0.1.2 → 0.1.3
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 +8 -34
- package/aegis.d.ts +246 -40
- package/dist/storage.js +1 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -16,10 +16,11 @@
|
|
|
16
16
|
- **Identity Management**: Create identities with specific userIds for better user correlation and management.
|
|
17
17
|
- **Key Rotation**: Supports identity rotation with option to maintain same userId or assign new ones.
|
|
18
18
|
- **Replay Protection**: Built-in protection against message replay attacks.
|
|
19
|
-
- **Minimal Dependencies**: Relies on robust, well-audited libraries like `@noble/curves` and `@noble/hashes`.
|
|
20
19
|
|
|
21
20
|
---
|
|
22
21
|
|
|
22
|
+
|
|
23
|
+
|
|
23
24
|
## **Installation**
|
|
24
25
|
|
|
25
26
|
Install the library using npm, yarn, or pnpm.
|
|
@@ -35,7 +36,10 @@ For React Native, you may need a
|
|
|
35
36
|
|
|
36
37
|
---
|
|
37
38
|
|
|
38
|
-
## **
|
|
39
|
+
## **Setup**
|
|
40
|
+
|
|
41
|
+
**Quick start**: Check [examples](/examples) for samples with browser, React Native, Electron, and Tauri
|
|
42
|
+
|
|
39
43
|
|
|
40
44
|
### **1. Implement a Storage Adapter**
|
|
41
45
|
|
|
@@ -217,8 +221,6 @@ console.log(new TextDecoder().decode(groupPlaintext)); // "Dinner at 8 PM!"
|
|
|
217
221
|
|
|
218
222
|
## **API Reference**
|
|
219
223
|
|
|
220
|
-
### **Core & Configuration**
|
|
221
|
-
|
|
222
224
|
### **Identity Management**
|
|
223
225
|
|
|
224
226
|
- **`aegis.createIdentity(userId?: string): Promise<{ identity, publicBundle }>`** - Creates a new identity with optional userId
|
|
@@ -250,10 +252,8 @@ console.log(new TextDecoder().decode(groupPlaintext)); // "Dinner at 8 PM!"
|
|
|
250
252
|
## **Testing and Examples**
|
|
251
253
|
|
|
252
254
|
- **Run All Tests**: `npm test`
|
|
253
|
-
- **Run
|
|
254
|
-
|
|
255
|
-
- **Run Benchmarks**: `npm run benchmark`
|
|
256
|
-
- Executes performance benchmarks for various operations including identity creation, session establishment, message encryption/decryption, and group operations.
|
|
255
|
+
- **Run peer messaging demo**: `npm run demo`
|
|
256
|
+
- **Run group messaging demo**: `npm run demo:group`
|
|
257
257
|
|
|
258
258
|
---
|
|
259
259
|
|
|
@@ -279,32 +279,6 @@ Aegis is built on a hybrid model:
|
|
|
279
279
|
|
|
280
280
|
---
|
|
281
281
|
|
|
282
|
-
## **Performance & Benchmarks**
|
|
283
|
-
|
|
284
|
-
Aegis includes comprehensive benchmarking to measure performance across various operations:
|
|
285
|
-
|
|
286
|
-
- **Identity Creation**: ~30-50ms per operation
|
|
287
|
-
- **Session Establishment**: ~25-50ms per operation
|
|
288
|
-
- **Message Encryption/Decryption**: ~30-70ms per round-trip
|
|
289
|
-
- **Group Operations**: ~40-130ms depending on group size
|
|
290
|
-
- **Ratchet Operations**: ~30-60ms per operation
|
|
291
|
-
|
|
292
|
-
Run `npm run benchmark` to see performance metrics on your system.
|
|
293
|
-
|
|
294
|
-
---
|
|
295
|
-
|
|
296
|
-
## **Contributing & Roadmap**
|
|
297
|
-
|
|
298
|
-
We welcome contributions. Priority areas include:
|
|
299
|
-
|
|
300
|
-
- Enhanced utilities for server-side OTPK lifecycle management.
|
|
301
|
-
- Improved examples for cross-platform secure storage.
|
|
302
|
-
- Advanced group management features (admin roles, permissions, etc.).
|
|
303
|
-
- Performance optimizations for large group messaging.
|
|
304
|
-
- Additional storage adapters for popular databases and platforms.
|
|
305
|
-
|
|
306
|
-
---
|
|
307
|
-
|
|
308
282
|
## **License**
|
|
309
283
|
|
|
310
284
|
MIT
|
package/aegis.d.ts
CHANGED
|
@@ -1,6 +1,250 @@
|
|
|
1
|
+
//Types
|
|
1
2
|
declare module "@immahq/aegis" {
|
|
2
|
-
export class Aegis {
|
|
3
|
-
|
|
3
|
+
export class Aegis {
|
|
4
|
+
constructor(storage: StorageAdapter);
|
|
5
|
+
createIdentity(userId?: string): Promise<AegisIdentity>;
|
|
6
|
+
getIdentity(): Promise<Identity>;
|
|
7
|
+
rotateIdentity(userId?: string): Promise<AegisIdentity>;
|
|
8
|
+
getPublicBundle(): Promise<PublicBundle>;
|
|
9
|
+
createSession(publicBundle: PublicBundle): Promise<{
|
|
10
|
+
sessionId: string;
|
|
11
|
+
ciphertext: Uint8Array;
|
|
12
|
+
confirmationMac: Uint8Array;
|
|
13
|
+
}>;
|
|
14
|
+
createResponderSession(
|
|
15
|
+
publicBundle: PublicBundle,
|
|
16
|
+
ciphertext: Uint8Array,
|
|
17
|
+
initiatorConfirmationMac?: Uint8Array,
|
|
18
|
+
): Promise<{
|
|
19
|
+
sessionId: string;
|
|
20
|
+
confirmationMac: Uint8Array;
|
|
21
|
+
isValid: boolean;
|
|
22
|
+
}>;
|
|
23
|
+
confirmSession(
|
|
24
|
+
sessionId: string,
|
|
25
|
+
responderConfirmationMac: Uint8Array,
|
|
26
|
+
): Promise<boolean>;
|
|
27
|
+
getSessions(): Promise<Session[]>;
|
|
28
|
+
cleanupOldSessions(maxAge?: number): Promise<void>;
|
|
29
|
+
encryptMessage(
|
|
30
|
+
sessionId: string,
|
|
31
|
+
plaintext: string | Uint8Array,
|
|
32
|
+
): Promise<EncryptedMessage>;
|
|
33
|
+
decryptMessage(
|
|
34
|
+
sessionId: string,
|
|
35
|
+
encrypted: EncryptedMessage,
|
|
36
|
+
): Promise<{
|
|
37
|
+
plaintext: Uint8Array;
|
|
38
|
+
needsConfirmation?: boolean;
|
|
39
|
+
}>;
|
|
40
|
+
triggerRatchet(sessionId: string): Promise<void>;
|
|
41
|
+
getReplayProtectionStatus(sessionId: string): Promise<{
|
|
42
|
+
storedMessageIds: number;
|
|
43
|
+
lastProcessedTimestamp: number;
|
|
44
|
+
replayWindowSize: number;
|
|
45
|
+
}>;
|
|
46
|
+
getConfirmationMac(sessionId: string): Promise<Uint8Array | null>;
|
|
47
|
+
getStorage(): StorageAdapter;
|
|
48
|
+
createGroup(
|
|
49
|
+
name: string,
|
|
50
|
+
members: string[],
|
|
51
|
+
memberKemPublicKeys: Map<string, Uint8Array>,
|
|
52
|
+
memberDsaPublicKeys: Map<string, Uint8Array>,
|
|
53
|
+
): Promise<Group>;
|
|
54
|
+
addGroupMember(
|
|
55
|
+
groupId: string,
|
|
56
|
+
userId: string,
|
|
57
|
+
session: Session,
|
|
58
|
+
userPublicKey: Uint8Array,
|
|
59
|
+
): Promise<void>;
|
|
60
|
+
removeGroupMember(groupId: string, userId: string): Promise<void>;
|
|
61
|
+
updateGroupKey(groupId: string): Promise<void>;
|
|
62
|
+
encryptGroupMessage(
|
|
63
|
+
groupId: string,
|
|
64
|
+
message: string | Uint8Array,
|
|
65
|
+
): Promise<GroupMessage>;
|
|
66
|
+
decryptGroupMessage(
|
|
67
|
+
groupId: string,
|
|
68
|
+
encrypted: GroupMessage,
|
|
69
|
+
): Promise<Uint8Array>;
|
|
70
|
+
getGroup(groupId: string): Promise<Group | null>;
|
|
71
|
+
getGroups(): Promise<Group[]>;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export class MemoryStorage implements StorageAdapter {
|
|
75
|
+
saveIdentity(identity: Identity): Promise<void>;
|
|
76
|
+
getIdentity(): Promise<Identity | null>;
|
|
77
|
+
deleteIdentity(): Promise<void>;
|
|
78
|
+
saveSession(sessionId: string, session: Session): Promise<void>;
|
|
79
|
+
getSession(sessionId: string): Promise<Session | null>;
|
|
80
|
+
deleteSession(sessionId: string): Promise<void>;
|
|
81
|
+
listSessions(): Promise<string[]>;
|
|
82
|
+
deleteAllSessions(): Promise<void>;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export class Logger {
|
|
86
|
+
static log(
|
|
87
|
+
component: string,
|
|
88
|
+
message: string,
|
|
89
|
+
data?: Record<string, any>,
|
|
90
|
+
): void;
|
|
91
|
+
static error(component: string, message: string, error?: any): void;
|
|
92
|
+
static warn(
|
|
93
|
+
component: string,
|
|
94
|
+
message: string,
|
|
95
|
+
data?: Record<string, any>,
|
|
96
|
+
): void;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export class KemRatchet {}
|
|
100
|
+
|
|
101
|
+
export class SessionKeyExchange {
|
|
102
|
+
static createInitiatorSession(
|
|
103
|
+
identity: Identity,
|
|
104
|
+
peerBundle: PublicBundle,
|
|
105
|
+
): {
|
|
106
|
+
sessionId: string;
|
|
107
|
+
rootKey: Uint8Array;
|
|
108
|
+
sendingChainKey: Uint8Array;
|
|
109
|
+
receivingChainKey: Uint8Array;
|
|
110
|
+
ciphertext: Uint8Array;
|
|
111
|
+
confirmationMac: Uint8Array;
|
|
112
|
+
};
|
|
113
|
+
static createResponderSession(
|
|
114
|
+
identity: Identity,
|
|
115
|
+
peerBundle: PublicBundle,
|
|
116
|
+
ciphertext: Uint8Array,
|
|
117
|
+
initiatorConfirmationMac?: Uint8Array,
|
|
118
|
+
): {
|
|
119
|
+
sessionId: string;
|
|
120
|
+
rootKey: Uint8Array;
|
|
121
|
+
sendingChainKey: Uint8Array;
|
|
122
|
+
receivingChainKey: Uint8Array;
|
|
123
|
+
confirmationMac: Uint8Array;
|
|
124
|
+
isValid: boolean;
|
|
125
|
+
};
|
|
126
|
+
static verifyKeyConfirmation(
|
|
127
|
+
sessionId: string,
|
|
128
|
+
rootKey: Uint8Array,
|
|
129
|
+
receivingChainKey: Uint8Array,
|
|
130
|
+
confirmationMac: Uint8Array,
|
|
131
|
+
): boolean;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
export class IdentityManager {
|
|
135
|
+
constructor(storage: StorageAdapter);
|
|
136
|
+
createIdentity(userId?: string): Promise<AegisIdentity>;
|
|
137
|
+
getIdentity(): Promise<Identity>;
|
|
138
|
+
getPublicBundle(): Promise<PublicBundle>;
|
|
139
|
+
rotateIdentity(userId?: string): Promise<AegisIdentity>;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
export class SessionManager {
|
|
143
|
+
constructor(storage: StorageAdapter);
|
|
144
|
+
createSession(
|
|
145
|
+
identity: Identity,
|
|
146
|
+
peerBundle: PublicBundle,
|
|
147
|
+
): Promise<{
|
|
148
|
+
sessionId: string;
|
|
149
|
+
ciphertext: Uint8Array;
|
|
150
|
+
confirmationMac: Uint8Array;
|
|
151
|
+
}>;
|
|
152
|
+
createResponderSession(
|
|
153
|
+
identity: Identity,
|
|
154
|
+
peerBundle: PublicBundle,
|
|
155
|
+
ciphertext: Uint8Array,
|
|
156
|
+
initiatorConfirmationMac?: Uint8Array,
|
|
157
|
+
): Promise<{
|
|
158
|
+
sessionId: string;
|
|
159
|
+
confirmationMac: Uint8Array;
|
|
160
|
+
isValid: boolean;
|
|
161
|
+
}>;
|
|
162
|
+
confirmSession(
|
|
163
|
+
sessionId: string,
|
|
164
|
+
responderConfirmationMac: Uint8Array,
|
|
165
|
+
): Promise<boolean>;
|
|
166
|
+
getSessions(): Promise<Session[]>;
|
|
167
|
+
cleanupOldSessions(maxAge?: number): Promise<void>;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
export class CryptoManager {
|
|
171
|
+
constructor(storage: StorageAdapter);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
export class RatchetManager {
|
|
175
|
+
shouldPerformSendingRatchet(session: Session): boolean;
|
|
176
|
+
performSendingRatchet(session: Session): Session;
|
|
177
|
+
needsReceivingRatchet(session: Session, header: any): boolean;
|
|
178
|
+
performReceivingRatchet(
|
|
179
|
+
session: Session,
|
|
180
|
+
kemCiphertext: Uint8Array,
|
|
181
|
+
): Session;
|
|
182
|
+
applyPendingRatchet(session: Session): Session;
|
|
183
|
+
getDecryptionChainForRatchetMessage(session: Session): RatchetChain | null;
|
|
184
|
+
triggerRatchet(sessionId: string, session: Session): Promise<Session>;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
export class ReplayProtection {
|
|
188
|
+
getSkippedKeyId(
|
|
189
|
+
ratchetPublicKey: Uint8Array,
|
|
190
|
+
messageNumber: number,
|
|
191
|
+
): string;
|
|
192
|
+
storeReceivedMessageId(session: Session, messageId: string): void;
|
|
193
|
+
cleanupSkippedKeys(session: Session): void;
|
|
194
|
+
getReplayProtectionStatus(
|
|
195
|
+
sessionId: string,
|
|
196
|
+
session: Session,
|
|
197
|
+
): Promise<{
|
|
198
|
+
storedMessageIds: number;
|
|
199
|
+
lastProcessedTimestamp: number;
|
|
200
|
+
replayWindowSize: number;
|
|
201
|
+
}>;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
export class GroupManager {
|
|
205
|
+
constructor(storage: StorageAdapter);
|
|
206
|
+
initialize(identity: Identity): Promise<void>;
|
|
207
|
+
createGroup(
|
|
208
|
+
name: string,
|
|
209
|
+
members: string[],
|
|
210
|
+
memberKemPublicKeys: Map<string, Uint8Array>,
|
|
211
|
+
memberDsaPublicKeys: Map<string, Uint8Array>,
|
|
212
|
+
): Promise<Group>;
|
|
213
|
+
addMember(
|
|
214
|
+
groupId: string,
|
|
215
|
+
userId: string,
|
|
216
|
+
session: Session,
|
|
217
|
+
userPublicKey: Uint8Array,
|
|
218
|
+
): Promise<void>;
|
|
219
|
+
removeMember(groupId: string, userId: string): Promise<void>;
|
|
220
|
+
updateGroupKey(groupId: string): Promise<void>;
|
|
221
|
+
encryptMessage(
|
|
222
|
+
groupId: string,
|
|
223
|
+
message: string | Uint8Array,
|
|
224
|
+
): Promise<GroupMessage>;
|
|
225
|
+
decryptMessage(
|
|
226
|
+
groupId: string,
|
|
227
|
+
encrypted: GroupMessage,
|
|
228
|
+
): Promise<Uint8Array>;
|
|
229
|
+
getGroup(groupId: string): Promise<Group | null>;
|
|
230
|
+
getGroups(): Promise<Group[]>;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
export interface AegisIdentity {
|
|
234
|
+
identity: Identity;
|
|
235
|
+
publicBundle: PublicBundle;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
export interface StorageAdapter {
|
|
239
|
+
saveIdentity(identity: Identity): Promise<void>;
|
|
240
|
+
getIdentity(): Promise<Identity | null>;
|
|
241
|
+
deleteIdentity(): Promise<void>;
|
|
242
|
+
saveSession(sessionId: string, session: Session): Promise<void>;
|
|
243
|
+
getSession(sessionId: string): Promise<Session | null>;
|
|
244
|
+
deleteSession(sessionId: string): Promise<void>;
|
|
245
|
+
listSessions(): Promise<string[]>;
|
|
246
|
+
deleteAllSessions(): Promise<void>;
|
|
247
|
+
}
|
|
4
248
|
|
|
5
249
|
export interface Identity {
|
|
6
250
|
kemKeyPair: { publicKey: Uint8Array; secretKey: Uint8Array };
|
|
@@ -109,17 +353,6 @@ declare module "@immahq/aegis" {
|
|
|
109
353
|
createdAt: number;
|
|
110
354
|
}
|
|
111
355
|
|
|
112
|
-
export interface StorageAdapter {
|
|
113
|
-
saveIdentity(identity: Identity): Promise<void>;
|
|
114
|
-
getIdentity(): Promise<Identity | null>;
|
|
115
|
-
deleteIdentity(): Promise<void>;
|
|
116
|
-
saveSession(sessionId: string, session: Session): Promise<void>;
|
|
117
|
-
getSession(sessionId: string): Promise<Session | null>;
|
|
118
|
-
deleteSession(sessionId: string): Promise<void>;
|
|
119
|
-
listSessions(): Promise<string[]>;
|
|
120
|
-
deleteAllSessions(): Promise<void>;
|
|
121
|
-
}
|
|
122
|
-
|
|
123
356
|
export interface KeyConfirmationData {
|
|
124
357
|
sessionId: string;
|
|
125
358
|
mac: Uint8Array;
|
|
@@ -169,31 +402,4 @@ declare module "@immahq/aegis" {
|
|
|
169
402
|
canManageMembers: boolean;
|
|
170
403
|
canUpdateGroup: boolean;
|
|
171
404
|
}
|
|
172
|
-
|
|
173
|
-
export interface GroupManager {
|
|
174
|
-
createGroup(
|
|
175
|
-
name: string,
|
|
176
|
-
members: string[],
|
|
177
|
-
memberKemPublicKeys: Map<string, Uint8Array>,
|
|
178
|
-
memberDsaPublicKeys: Map<string, Uint8Array>,
|
|
179
|
-
): Promise<Group>;
|
|
180
|
-
addMember(
|
|
181
|
-
groupId: string,
|
|
182
|
-
userId: string,
|
|
183
|
-
session: Session,
|
|
184
|
-
userPublicKey: Uint8Array,
|
|
185
|
-
): Promise<void>;
|
|
186
|
-
removeMember(groupId: string, userId: string): Promise<void>;
|
|
187
|
-
updateGroupKey(groupId: string): Promise<void>;
|
|
188
|
-
encryptMessage(
|
|
189
|
-
groupId: string,
|
|
190
|
-
message: string | Uint8Array,
|
|
191
|
-
): Promise<GroupMessage>;
|
|
192
|
-
decryptMessage(
|
|
193
|
-
groupId: string,
|
|
194
|
-
encrypted: GroupMessage,
|
|
195
|
-
): Promise<Uint8Array>;
|
|
196
|
-
getGroup(groupId: string): Promise<Group | null>;
|
|
197
|
-
getGroups(): Promise<Group[]>;
|
|
198
|
-
}
|
|
199
405
|
}
|
package/dist/storage.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@immahq/aegis",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"description": "Lightweight, storage-agnostic library for client-side End-to-End (E2E) encryption",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -33,6 +33,7 @@
|
|
|
33
33
|
"cryptography",
|
|
34
34
|
"encryption",
|
|
35
35
|
"e2e",
|
|
36
|
+
"e2ee",
|
|
36
37
|
"end-to-end",
|
|
37
38
|
"pqc",
|
|
38
39
|
"post-quantum",
|
|
@@ -52,7 +53,6 @@
|
|
|
52
53
|
"buffer": "^6.0.3"
|
|
53
54
|
},
|
|
54
55
|
"devDependencies": {
|
|
55
|
-
"@types/node": "^25.0.3",
|
|
56
56
|
"rimraf": "^6.1.2",
|
|
57
57
|
"tsx": "^4.21.0",
|
|
58
58
|
"typescript": "^5.9.3",
|