@immahq/aegis 0.0.2 → 0.0.5
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 +7 -5
- package/aegis.d.ts +196 -0
- package/dist/crypto-manager.js +4 -4
- package/dist/e2ee.js +7 -7
- package/dist/group-manager.js +3 -4
- package/dist/identity-manager.js +3 -3
- package/dist/index.js +11 -11
- package/dist/ratchet-manager.js +3 -3
- package/dist/replay-protection.js +1 -1
- package/dist/session-manager.js +4 -4
- package/package.json +7 -8
package/README.md
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
# **Aegis**
|
|
1
|
+
# **Aegis**
|
|
2
|
+
[](https://app.codacy.com/gh/imma-hq/aegis/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_grade)
|
|
3
|
+

|
|
2
4
|
|
|
3
5
|
**Aegis** is a lightweight, storage-agnostic library for client-side End-to-End (E2E) encryption, designed for future security. It combines the NIST-standardized ML-KEM 768 algorithm for quantum-resistant key agreement with high-performance symmetric cryptography (ChaCha20-Poly1305, Blake3) to provide secure 1:1 sessions and scalable group messaging.
|
|
4
6
|
|
|
5
7
|
---
|
|
6
8
|
|
|
7
|
-

|
|
8
|
-

|
|
9
9
|
|
|
10
10
|
## **Core Features**
|
|
11
11
|
|
|
12
|
-
- **Post-Quantum Ready**: Uses **ML-KEM 768
|
|
12
|
+
- **Post-Quantum Ready**: Uses **ML-KEM 768** for initial key encapsulation, aligning with NIST standards.
|
|
13
13
|
- **Storage-Agnostic**: You provide a simple key-value storage adapter (e.g., AsyncStorage, LocalStorage, SQLite, SecureStore).
|
|
14
14
|
- **Modern Cryptography**: Symmetric ratchets for forward secrecy and Sender Keys for O(1) group encryption.
|
|
15
15
|
- **Enhanced Security**: Implements proper group key encryption, pre-key signature verification, and secure group membership protocols.
|
|
@@ -26,6 +26,8 @@ npm install @immahq/aegis
|
|
|
26
26
|
# or
|
|
27
27
|
yarn add @immahq/aegis
|
|
28
28
|
```
|
|
29
|
+
For React Native, you may need a
|
|
30
|
+
[polyfill for getRandomValues](https://github.com/LinusU/react-native-get-random-values).
|
|
29
31
|
|
|
30
32
|
---
|
|
31
33
|
|
|
@@ -229,7 +231,7 @@ console.log(new TextDecoder().decode(groupPlaintext)); // "Dinner at 8 PM!"
|
|
|
229
231
|
|
|
230
232
|
Aegis is built on a hybrid model:
|
|
231
233
|
|
|
232
|
-
1. **Key Agreement**: **ML-KEM 768
|
|
234
|
+
1. **Key Agreement**: **ML-KEM 768** provides quantum-resistant key encapsulation. This algorithm is now a finalized NIST standard (FIPS 203).
|
|
233
235
|
2. **Data Encryption**: **ChaCha20-Poly1305** is used for fast, authenticated encryption of message contents.
|
|
234
236
|
3. **Key Derivation & Hashing**: **Blake3** is used for key derivation and hashing, providing high speed and security.
|
|
235
237
|
|
package/aegis.d.ts
ADDED
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
declare module "@immahq/aegis" {
|
|
2
|
+
export interface Identity {
|
|
3
|
+
kemKeyPair: { publicKey: Uint8Array; secretKey: Uint8Array };
|
|
4
|
+
dsaKeyPair: { publicKey: Uint8Array; secretKey: Uint8Array };
|
|
5
|
+
userId: string;
|
|
6
|
+
createdAt: number;
|
|
7
|
+
preKeySecret?: Uint8Array;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface PublicBundle {
|
|
11
|
+
userId: string;
|
|
12
|
+
kemPublicKey: Uint8Array;
|
|
13
|
+
dsaPublicKey: Uint8Array;
|
|
14
|
+
preKey: {
|
|
15
|
+
id: number;
|
|
16
|
+
key: Uint8Array;
|
|
17
|
+
signature: Uint8Array;
|
|
18
|
+
};
|
|
19
|
+
createdAt: number;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface RatchetChain {
|
|
23
|
+
chainKey: Uint8Array;
|
|
24
|
+
messageNumber: number;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface SkippedMessageKey {
|
|
28
|
+
messageKey: Uint8Array;
|
|
29
|
+
timestamp: number;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export interface PendingRatchetState {
|
|
33
|
+
newRootKey: Uint8Array;
|
|
34
|
+
newRatchetKeyPair: { publicKey: Uint8Array; secretKey: Uint8Array };
|
|
35
|
+
sendingChain: RatchetChain;
|
|
36
|
+
receivingChain: RatchetChain;
|
|
37
|
+
kemCiphertext: Uint8Array;
|
|
38
|
+
previousReceivingChain: RatchetChain | null;
|
|
39
|
+
previousSendingChain: RatchetChain | null;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export interface Session {
|
|
43
|
+
sessionId: string;
|
|
44
|
+
peerUserId: string;
|
|
45
|
+
peerDsaPublicKey: Uint8Array;
|
|
46
|
+
rootKey: Uint8Array;
|
|
47
|
+
currentRatchetKeyPair: {
|
|
48
|
+
publicKey: Uint8Array;
|
|
49
|
+
secretKey: Uint8Array;
|
|
50
|
+
} | null;
|
|
51
|
+
peerRatchetPublicKey: Uint8Array | null;
|
|
52
|
+
|
|
53
|
+
pendingRatchetState?: PendingRatchetState;
|
|
54
|
+
|
|
55
|
+
sendingChain: RatchetChain | null;
|
|
56
|
+
receivingChain: RatchetChain | null;
|
|
57
|
+
previousSendingChainLength: number;
|
|
58
|
+
skippedMessageKeys: Map<string, SkippedMessageKey>;
|
|
59
|
+
highestReceivedMessageNumber: number;
|
|
60
|
+
maxSkippedMessages: number;
|
|
61
|
+
createdAt: number;
|
|
62
|
+
lastUsed: number;
|
|
63
|
+
isInitiator: boolean;
|
|
64
|
+
ratchetCount: number;
|
|
65
|
+
state: "CREATED" | "KEY_CONFIRMED" | "ACTIVE" | "RATCHET_PENDING" | "ERROR";
|
|
66
|
+
confirmed: boolean;
|
|
67
|
+
confirmationMac?: Uint8Array;
|
|
68
|
+
|
|
69
|
+
receivedMessageIds: Set<string>;
|
|
70
|
+
replayWindowSize: number;
|
|
71
|
+
lastProcessedTimestamp: number;
|
|
72
|
+
|
|
73
|
+
groupData?: {
|
|
74
|
+
name: string;
|
|
75
|
+
members: string[];
|
|
76
|
+
owner: string;
|
|
77
|
+
memberKeys: [string, Uint8Array][];
|
|
78
|
+
memberPublicKeys: [string, Uint8Array][]; // KEM public keys for key encryption
|
|
79
|
+
memberDsaPublicKeys?: [string, Uint8Array][]; // DSA public keys for signature verification
|
|
80
|
+
receivedMessageNumbers?: [string, number][];
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export interface MessageHeader {
|
|
85
|
+
messageId: string;
|
|
86
|
+
ratchetPublicKey: Uint8Array;
|
|
87
|
+
messageNumber: number;
|
|
88
|
+
previousChainLength: number;
|
|
89
|
+
kemCiphertext?: Uint8Array;
|
|
90
|
+
isRatchetMessage?: boolean;
|
|
91
|
+
timestamp: number;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export interface EncryptedMessage {
|
|
95
|
+
ciphertext: Uint8Array;
|
|
96
|
+
header: MessageHeader;
|
|
97
|
+
signature: Uint8Array;
|
|
98
|
+
confirmationMac?: Uint8Array;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export interface PreKey {
|
|
102
|
+
id: number;
|
|
103
|
+
keyPair: { publicKey: Uint8Array; secretKey: Uint8Array };
|
|
104
|
+
signature: Uint8Array;
|
|
105
|
+
used: boolean;
|
|
106
|
+
createdAt: number;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export interface StorageAdapter {
|
|
110
|
+
saveIdentity(identity: Identity): Promise<void>;
|
|
111
|
+
getIdentity(): Promise<Identity | null>;
|
|
112
|
+
deleteIdentity(): Promise<void>;
|
|
113
|
+
saveSession(sessionId: string, session: Session): Promise<void>;
|
|
114
|
+
getSession(sessionId: string): Promise<Session | null>;
|
|
115
|
+
deleteSession(sessionId: string): Promise<void>;
|
|
116
|
+
listSessions(): Promise<string[]>;
|
|
117
|
+
deleteAllSessions(): Promise<void>;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export interface KeyConfirmationData {
|
|
121
|
+
sessionId: string;
|
|
122
|
+
mac: Uint8Array;
|
|
123
|
+
timestamp: number;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
export interface Group {
|
|
127
|
+
groupId: string;
|
|
128
|
+
name: string;
|
|
129
|
+
members: string[];
|
|
130
|
+
sharedKey: Uint8Array;
|
|
131
|
+
createdAt: number;
|
|
132
|
+
lastUpdated: number;
|
|
133
|
+
owner: string;
|
|
134
|
+
memberKeys: Map<string, Uint8Array>;
|
|
135
|
+
memberPublicKeys: Map<string, Uint8Array>; // KEM public keys for key encryption
|
|
136
|
+
memberDsaPublicKeys: Map<string, Uint8Array>; // DSA public keys for signature verification
|
|
137
|
+
receivedMessageNumbers: Map<string, number>;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
export interface GroupMessage {
|
|
141
|
+
groupId: string;
|
|
142
|
+
message: Uint8Array;
|
|
143
|
+
header: GroupMessageHeader;
|
|
144
|
+
signature: Uint8Array;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
export interface GroupMessageHeader {
|
|
148
|
+
messageId: string;
|
|
149
|
+
timestamp: number;
|
|
150
|
+
senderId: string;
|
|
151
|
+
messageNumber: number;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
export interface GroupSession {
|
|
155
|
+
sessionId: string;
|
|
156
|
+
groupId: string;
|
|
157
|
+
userId: string;
|
|
158
|
+
sharedKey: Uint8Array;
|
|
159
|
+
lastUsed: number;
|
|
160
|
+
permissions: GroupPermissions;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
export interface GroupPermissions {
|
|
164
|
+
canSend: boolean;
|
|
165
|
+
canReceive: boolean;
|
|
166
|
+
canManageMembers: boolean;
|
|
167
|
+
canUpdateGroup: boolean;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
export interface GroupManager {
|
|
171
|
+
createGroup(
|
|
172
|
+
name: string,
|
|
173
|
+
members: string[],
|
|
174
|
+
memberKemPublicKeys: Map<string, Uint8Array>,
|
|
175
|
+
memberDsaPublicKeys: Map<string, Uint8Array>
|
|
176
|
+
): Promise<Group>;
|
|
177
|
+
addMember(
|
|
178
|
+
groupId: string,
|
|
179
|
+
userId: string,
|
|
180
|
+
session: Session,
|
|
181
|
+
userPublicKey: Uint8Array
|
|
182
|
+
): Promise<void>;
|
|
183
|
+
removeMember(groupId: string, userId: string): Promise<void>;
|
|
184
|
+
updateGroupKey(groupId: string): Promise<void>;
|
|
185
|
+
encryptMessage(
|
|
186
|
+
groupId: string,
|
|
187
|
+
message: string | Uint8Array
|
|
188
|
+
): Promise<GroupMessage>;
|
|
189
|
+
decryptMessage(
|
|
190
|
+
groupId: string,
|
|
191
|
+
encrypted: GroupMessage
|
|
192
|
+
): Promise<Uint8Array>;
|
|
193
|
+
getGroup(groupId: string): Promise<Group | null>;
|
|
194
|
+
getGroups(): Promise<Group[]>;
|
|
195
|
+
}
|
|
196
|
+
}
|
package/dist/crypto-manager.js
CHANGED
|
@@ -3,10 +3,10 @@ import { ml_dsa65 } from "@noble/post-quantum/ml-dsa.js";
|
|
|
3
3
|
import { blake3 } from "@noble/hashes/blake3.js";
|
|
4
4
|
import { randomBytes } from "@noble/post-quantum/utils.js";
|
|
5
5
|
import { bytesToHex, concatBytes, utf8ToBytes } from "@noble/hashes/utils.js";
|
|
6
|
-
import { Logger } from "./logger
|
|
7
|
-
import { ERRORS, MAX_MESSAGE_AGE } from "./constants
|
|
8
|
-
import { serializeHeader } from "./utils
|
|
9
|
-
import { KemRatchet } from "./ratchet
|
|
6
|
+
import { Logger } from "./logger";
|
|
7
|
+
import { ERRORS, MAX_MESSAGE_AGE } from "./constants";
|
|
8
|
+
import { serializeHeader } from "./utils";
|
|
9
|
+
import { KemRatchet } from "./ratchet";
|
|
10
10
|
export class CryptoManager {
|
|
11
11
|
constructor(storage) {
|
|
12
12
|
Object.defineProperty(this, "storage", {
|
package/dist/e2ee.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { Logger } from "./logger
|
|
2
|
-
import { IdentityManager } from "./identity-manager
|
|
3
|
-
import { SessionManager } from "./session-manager
|
|
4
|
-
import { CryptoManager } from "./crypto-manager
|
|
5
|
-
import { RatchetManager } from "./ratchet-manager
|
|
6
|
-
import { ReplayProtection } from "./replay-protection
|
|
7
|
-
import { GroupManager } from "./group-manager
|
|
1
|
+
import { Logger } from "./logger";
|
|
2
|
+
import { IdentityManager } from "./identity-manager";
|
|
3
|
+
import { SessionManager } from "./session-manager";
|
|
4
|
+
import { CryptoManager } from "./crypto-manager";
|
|
5
|
+
import { RatchetManager } from "./ratchet-manager";
|
|
6
|
+
import { ReplayProtection } from "./replay-protection";
|
|
7
|
+
import { GroupManager } from "./group-manager";
|
|
8
8
|
export class E2EE {
|
|
9
9
|
constructor(storage) {
|
|
10
10
|
Object.defineProperty(this, "identityManager", {
|
package/dist/group-manager.js
CHANGED
|
@@ -3,8 +3,8 @@ import { ml_dsa65 } from "@noble/post-quantum/ml-dsa.js";
|
|
|
3
3
|
import { blake3 } from "@noble/hashes/blake3.js";
|
|
4
4
|
import { randomBytes } from "@noble/post-quantum/utils.js";
|
|
5
5
|
import { bytesToHex, concatBytes, utf8ToBytes } from "@noble/hashes/utils.js";
|
|
6
|
-
import { Logger } from "./logger
|
|
7
|
-
import { MAX_MESSAGE_AGE } from "./constants
|
|
6
|
+
import { Logger } from "./logger";
|
|
7
|
+
import { MAX_MESSAGE_AGE } from "./constants";
|
|
8
8
|
export class GroupManager {
|
|
9
9
|
constructor(storage) {
|
|
10
10
|
Object.defineProperty(this, "storage", {
|
|
@@ -124,8 +124,7 @@ export class GroupManager {
|
|
|
124
124
|
return group;
|
|
125
125
|
}
|
|
126
126
|
async addMember(groupId, userId, _session, // Unused parameter, using underscore prefix
|
|
127
|
-
userPublicKey
|
|
128
|
-
) {
|
|
127
|
+
userPublicKey) {
|
|
129
128
|
if (!this.identity) {
|
|
130
129
|
throw new Error("GroupManager not initialized with identity");
|
|
131
130
|
}
|
package/dist/identity-manager.js
CHANGED
|
@@ -2,9 +2,9 @@ import { ml_kem768 } from "@noble/post-quantum/ml-kem.js";
|
|
|
2
2
|
import { ml_dsa65 } from "@noble/post-quantum/ml-dsa.js";
|
|
3
3
|
import { blake3 } from "@noble/hashes/blake3.js";
|
|
4
4
|
import { bytesToHex, concatBytes } from "@noble/hashes/utils.js";
|
|
5
|
-
import { Logger } from "./logger
|
|
6
|
-
import { PreKeyManager } from "./prekey-manager
|
|
7
|
-
import { ERRORS } from "./constants
|
|
5
|
+
import { Logger } from "./logger";
|
|
6
|
+
import { PreKeyManager } from "./prekey-manager";
|
|
7
|
+
import { ERRORS } from "./constants";
|
|
8
8
|
export class IdentityManager {
|
|
9
9
|
constructor(storage) {
|
|
10
10
|
Object.defineProperty(this, "storage", {
|
package/dist/index.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
export { E2EE as Aegis } from "./e2ee
|
|
2
|
-
export { MemoryStorage } from "./storage
|
|
3
|
-
export { Logger } from "./logger
|
|
4
|
-
export { KemRatchet } from "./ratchet
|
|
5
|
-
export { SessionKeyExchange } from "./session
|
|
6
|
-
export { IdentityManager } from "./identity-manager
|
|
7
|
-
export { SessionManager } from "./session-manager
|
|
8
|
-
export { CryptoManager } from "./crypto-manager
|
|
9
|
-
export { RatchetManager } from "./ratchet-manager
|
|
10
|
-
export { ReplayProtection } from "./replay-protection
|
|
11
|
-
export { GroupManager } from "./group-manager
|
|
1
|
+
export { E2EE as Aegis } from "./e2ee";
|
|
2
|
+
export { MemoryStorage } from "./storage";
|
|
3
|
+
export { Logger } from "./logger";
|
|
4
|
+
export { KemRatchet } from "./ratchet";
|
|
5
|
+
export { SessionKeyExchange } from "./session";
|
|
6
|
+
export { IdentityManager } from "./identity-manager";
|
|
7
|
+
export { SessionManager } from "./session-manager";
|
|
8
|
+
export { CryptoManager } from "./crypto-manager";
|
|
9
|
+
export { RatchetManager } from "./ratchet-manager";
|
|
10
|
+
export { ReplayProtection } from "./replay-protection";
|
|
11
|
+
export { GroupManager } from "./group-manager";
|
package/dist/ratchet-manager.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { bytesToHex } from "@noble/hashes/utils.js";
|
|
2
|
-
import { Logger } from "./logger
|
|
3
|
-
import { RATCHET_AFTER_MESSAGES } from "./constants
|
|
4
|
-
import { KemRatchet } from "./ratchet
|
|
2
|
+
import { Logger } from "./logger";
|
|
3
|
+
import { RATCHET_AFTER_MESSAGES } from "./constants";
|
|
4
|
+
import { KemRatchet } from "./ratchet";
|
|
5
5
|
export class RatchetManager {
|
|
6
6
|
shouldPerformSendingRatchet(session) {
|
|
7
7
|
const messageCount = session.sendingChain?.messageNumber || 0;
|
package/dist/session-manager.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { ml_kem768 } from "@noble/post-quantum/ml-kem.js";
|
|
2
2
|
import { ml_dsa65 } from "@noble/post-quantum/ml-dsa.js";
|
|
3
|
-
import { Logger } from "./logger
|
|
4
|
-
import { ERRORS } from "./constants
|
|
5
|
-
import { SessionKeyExchange } from "./session
|
|
6
|
-
import { validatePublicBundle } from "./utils
|
|
3
|
+
import { Logger } from "./logger";
|
|
4
|
+
import { ERRORS } from "./constants";
|
|
5
|
+
import { SessionKeyExchange } from "./session";
|
|
6
|
+
import { validatePublicBundle } from "./utils";
|
|
7
7
|
export class SessionManager {
|
|
8
8
|
constructor(storage) {
|
|
9
9
|
Object.defineProperty(this, "storage", {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@immahq/aegis",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.5",
|
|
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",
|
|
@@ -12,7 +12,8 @@
|
|
|
12
12
|
}
|
|
13
13
|
},
|
|
14
14
|
"files": [
|
|
15
|
-
"dist"
|
|
15
|
+
"dist",
|
|
16
|
+
"aegis.d.ts"
|
|
16
17
|
],
|
|
17
18
|
"publishConfig": {
|
|
18
19
|
"access": "public"
|
|
@@ -29,12 +30,10 @@
|
|
|
29
30
|
"url": "git+ssh://git@github.com/imma-hq/aegis.git"
|
|
30
31
|
},
|
|
31
32
|
"keywords": [
|
|
32
|
-
"
|
|
33
|
-
"
|
|
34
|
-
"
|
|
35
|
-
"
|
|
36
|
-
"dropdown",
|
|
37
|
-
"option"
|
|
33
|
+
"cryptography",
|
|
34
|
+
"encryption",
|
|
35
|
+
"e2e",
|
|
36
|
+
"end-to-end"
|
|
38
37
|
],
|
|
39
38
|
"author": "Aegis",
|
|
40
39
|
"license": "MIT",
|