@crossdyne/security 0.5.0-beta.1 → 1.0.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 CHANGED
@@ -1,15 +1,365 @@
1
- # @quantropic/security
1
+ # Crossdyne.Security
2
2
 
3
- Security library with SRP authentication and cryptography utilities.
3
+ > Cross-platform cryptographic library — [.NET](https://github.com/crossdyne/dotnet-security) | [TypeScript](https://github.com/crossdyne/typescript-security)
4
+ >
5
+ > [English](#english) | [Русский](#русский)
4
6
 
5
- ## Features
7
+ ---
6
8
 
7
- - SRP (Secure Remote Password) protocol implementation
8
- - Cryptographic utilities
9
- - Key derivation functions
9
+ <a name="english"></a>
10
+ ## English
11
+
12
+ TypeScript / JavaScript implementation of the Crossdyne.Security cryptographic library via the native **Web Crypto API**.
10
13
 
11
14
  ## Installation
12
15
 
13
16
  ```bash
14
- npm install @quantropic/security
15
- ```
17
+ npm install @crossdyne/security
18
+ ```
19
+
20
+ ### Features
21
+
22
+ - **AES-256-GCM** — authenticated symmetric encryption via `crypto.subtle`
23
+ - **PBKDF2 + HKDF** — secure key derivation from passwords
24
+ - **SRP-6a** — password-authenticated key exchange without sending the password to the server
25
+ - **Zero-memory** — sensitive buffers are explicitly overwritten after use
26
+ - **No custom crypto primitives** — relies entirely on the browser / Node.js Web Crypto API
27
+ - **Cross-platform** — compatible with the [.NET implementation](https://github.com/crossdyne/dotnet-security). Encrypted payloads and SRP messages are interchangeable between TS and .NET.
28
+
29
+ ### Requirements
30
+
31
+ - TypeScript 5.3+
32
+ - Web Crypto API (`crypto.subtle`) — modern browsers and Node.js 18+
33
+
34
+ ### Project Structure
35
+
36
+ ```
37
+ crossdyne-security/
38
+ ├── crypto/
39
+ │ ├── crypto-service.ts # AES-GCM encrypt / decrypt
40
+ │ ├── key-derivation-service.ts # Derive KEK and AuthHash (PBKDF2 → HKDF)
41
+ │ ├── crypto-profile-registry.ts # Versioned crypto profiles
42
+ │ ├── crypto-version.ts # Enum: V1, V2, ...
43
+ │ └── kdf-options.ts # PBKDF2 / HKDF parameters
44
+ ├── srp/
45
+ │ ├── srp-server-service.ts # SRP server (challenge, verify)
46
+ │ ├── srp-client-service.ts # SRP client (proof, verifier)
47
+ │ ├── srp-key-derivation-service.ts # Derive auth-hash for SRP
48
+ │ ├── srp-context-factory.ts # Creates SRP context (N, g, k, hash)
49
+ │ ├── srp-group.ts # Enum: Group2048, Group4096, ...
50
+ │ └── srp-encoding.ts # BigInt ↔ bytes helpers
51
+ └── utils/
52
+ ├── security-utils.ts # Base64, BigInt, fixed-time compare
53
+ └── srp-encoding.ts # Hash moduli, session key, M1 / M2
54
+ ```
55
+
56
+ ### Quick Start
57
+
58
+ #### Encrypt / Decrypt
59
+
60
+ ```typescript
61
+ import { CryptoService } from './crypto/crypto-service.js';
62
+ import { CryptoVersion } from './crypto/crypto-version.js';
63
+
64
+ const crypto = new CryptoService();
65
+ const key = crypto.generateRandomBytes(32); // AES-256
66
+
67
+ const encrypted = await crypto.encryptData(
68
+ { message: "Hello, World!" },
69
+ key,
70
+ CryptoVersion.V1
71
+ );
72
+
73
+ const decrypted = await crypto.decryptData<MyData>(encrypted, key);
74
+ ```
75
+
76
+ Encrypted payload format (Base64):
77
+
78
+ ```
79
+ [Version (1 byte)][Nonce (N bytes)][Ciphertext + Tag]
80
+ ```
81
+
82
+ #### Key Derivation from Password
83
+
84
+ ```typescript
85
+ import { KeyDerivationService } from './crypto/key-derivation-service.js';
86
+ import { CryptoVersion } from './crypto/crypto-version.js';
87
+
88
+ const kdf = new KeyDerivationService();
89
+ const salt = crypto.getRandomValues(new Uint8Array(16));
90
+
91
+ const { kek, authHash } = await kdf.deriveKeysFromPassword(
92
+ "user@example.com",
93
+ "SuperSecret123!",
94
+ salt,
95
+ CryptoVersion.V1
96
+ );
97
+ ```
98
+
99
+ - `kek` — `Uint8Array` key for AES-GCM
100
+ - `authHash` — Base64 string for SRP authentication
101
+
102
+ #### SRP Authentication Flow
103
+
104
+ **Server — generate challenge**
105
+
106
+ ```typescript
107
+ import { SrpServerService } from './srp/srp-server-service.js';
108
+ import { SrpGroup } from './srp/srp-group.js';
109
+
110
+ const server = new SrpServerService();
111
+
112
+ const session = await server.getSrpChallenge(
113
+ "user@example.com",
114
+ verifierBytes,
115
+ salt,
116
+ SrpGroup.Group2048
117
+ );
118
+
119
+ // Send to client: salt + session.publicKeyB (B)
120
+ ```
121
+
122
+ **Client — generate proof**
123
+
124
+ ```typescript
125
+ import { SrpClientService } from './srp/srp-client-service.js';
126
+ import { SrpKeyDerivationService } from './srp/srp-key-derivation-service.js';
127
+ import { SrpGroup } from './srp/srp-group.js';
128
+ import { CryptoVersion } from './crypto/crypto-version.js';
129
+
130
+ const client = new SrpClientService();
131
+ const kdf = new SrpKeyDerivationService();
132
+
133
+ // 1. Derive auth-hash from password
134
+ const authHash = await kdf.deriveAuthHashForSrp(
135
+ identity, password, salt, SrpGroup.Group2048, CryptoVersion.V1
136
+ );
137
+
138
+ // 2. Generate proof
139
+ const { A, M1, SessionKeyK } = await client.generateSrpProof(
140
+ identity,
141
+ authHash,
142
+ btoa(String.fromCharCode(...salt)),
143
+ btoa(String.fromCharCode(...session.publicKeyB)),
144
+ SrpGroup.Group2048
145
+ );
146
+
147
+ // Send to server: A + M1
148
+ ```
149
+
150
+ **Server — verify proof**
151
+
152
+ ```typescript
153
+ const serverM2 = await server.verifySrpProof(
154
+ session,
155
+ A,
156
+ M1,
157
+ SrpGroup.Group2048
158
+ );
159
+
160
+ // Send to client: serverM2
161
+ ```
162
+
163
+ **Client — verify server proof**
164
+
165
+ ```typescript
166
+ const isValid = await client.verifyServerM2(
167
+ A,
168
+ M1,
169
+ SessionKeyK,
170
+ serverM2,
171
+ SrpGroup.Group2048
172
+ );
173
+ ```
174
+
175
+ ### Security Notes
176
+
177
+ - All sensitive buffers are explicitly overwritten after use
178
+ - Salt must be **at least 16 bytes**
179
+ - AES-256 key must be **exactly 32 bytes**
180
+ - SRP groups are protected against small-subgroup attacks (checks `A % N != 0`, `B != 0`)
181
+ - Relies entirely on the native Web Crypto API — no custom crypto primitives
182
+
183
+ ### License
184
+
185
+ MIT
186
+
187
+ ---
188
+
189
+ <a name="русский"></a>
190
+ ## Русский
191
+
192
+ Реализация криптографической библиотеки Crossdyne.Security для TypeScript / JavaScript через нативный **Web Crypto API**.
193
+
194
+ ## Установка
195
+
196
+ ```bash
197
+ npm install @crossdyne/security
198
+ ```
199
+
200
+ ### Возможности
201
+
202
+ - **AES-256-GCM** — симметричное шифрование с аутентификацией через `crypto.subtle`
203
+ - **PBKDF2 + HKDF** — надёжный вывод ключей из пароля
204
+ - **SRP-6a** — протокол аутентификации без передачи пароля на сервер
205
+ - **Zero-memory** — чувствительные буферы явно перезаписываются после использования
206
+ - **Никаких самописных криптопримитивов** — только нативный Web Crypto API браузера / Node.js
207
+ - **Кроссплатформенность** — совместима с [.NET-реализацией](https://github.com/crossdyne/dotnet-security). Зашифрованные данные и SRP-сообщения взаимозаменяемы между TS и .NET.
208
+
209
+ ### Требования
210
+
211
+ - TypeScript 5.3+
212
+ - Web Crypto API (`crypto.subtle`) — современные браузеры и Node.js 18+
213
+
214
+ ### Структура проекта
215
+
216
+ ```
217
+ crossdyne-security/
218
+ ├── crypto/
219
+ │ ├── crypto-service.ts # AES-GCM шифрование / дешифрование
220
+ │ ├── key-derivation-service.ts # Вывод KEK и AuthHash (PBKDF2 → HKDF)
221
+ │ ├── crypto-profile-registry.ts # Версионированные криптопрофили
222
+ │ ├── crypto-version.ts # Enum: V1, V2, ...
223
+ │ └── kdf-options.ts # Параметры PBKDF2 / HKDF
224
+ ├── srp/
225
+ │ ├── srp-server-service.ts # SRP сервер (challenge, проверка)
226
+ │ ├── srp-client-service.ts # SRP клиент (proof, верификатор)
227
+ │ ├── srp-key-derivation-service.ts # Вывод auth-hash для SRP
228
+ │ ├── srp-context-factory.ts # Создание SRP-контекста (N, g, k, hash)
229
+ │ ├── srp-group.ts # Enum: Group2048, Group4096, ...
230
+ │ └── srp-encoding.ts # BigInt ↔ bytes хелперы
231
+ └── utils/
232
+ ├── security-utils.ts # Base64, BigInt, сравнение в постоянное время
233
+ └── srp-encoding.ts # Хеш модулей, сессионный ключ, M1 / M2
234
+ ```
235
+
236
+ ### Быстрый старт
237
+
238
+ #### Шифрование / дешифрование
239
+
240
+ ```typescript
241
+ import { CryptoService } from './crypto/crypto-service.js';
242
+ import { CryptoVersion } from './crypto/crypto-version.js';
243
+
244
+ const crypto = new CryptoService();
245
+ const key = crypto.generateRandomBytes(32); // AES-256
246
+
247
+ const encrypted = await crypto.encryptData(
248
+ { message: "Hello, World!" },
249
+ key,
250
+ CryptoVersion.V1
251
+ );
252
+
253
+ const decrypted = await crypto.decryptData<MyData>(encrypted, key);
254
+ ```
255
+
256
+ Формат зашифрованных данных (Base64):
257
+
258
+ ```
259
+ [Version (1 byte)][Nonce (N bytes)][Ciphertext + Tag]
260
+ ```
261
+
262
+ #### Вывод ключей из пароля
263
+
264
+ ```typescript
265
+ import { KeyDerivationService } from './crypto/key-derivation-service.js';
266
+ import { CryptoVersion } from './crypto/crypto-version.js';
267
+
268
+ const kdf = new KeyDerivationService();
269
+ const salt = crypto.getRandomValues(new Uint8Array(16));
270
+
271
+ const { kek, authHash } = await kdf.deriveKeysFromPassword(
272
+ "user@example.com",
273
+ "SuperSecret123!",
274
+ salt,
275
+ CryptoVersion.V1
276
+ );
277
+ ```
278
+
279
+ - `kek` — `Uint8Array` ключ для AES-GCM
280
+ - `authHash` — Base64-строка для SRP-аутентификации
281
+
282
+ #### SRP-аутентификация
283
+
284
+ **Сервер — генерация challenge**
285
+
286
+ ```typescript
287
+ import { SrpServerService } from './srp/srp-server-service.js';
288
+ import { SrpGroup } from './srp/srp-group.js';
289
+
290
+ const server = new SrpServerService();
291
+
292
+ const session = await server.getSrpChallenge(
293
+ "user@example.com",
294
+ verifierBytes,
295
+ salt,
296
+ SrpGroup.Group2048
297
+ );
298
+
299
+ // Отправить клиенту: salt + session.publicKeyB (B)
300
+ ```
301
+
302
+ **Клиент — генерация proof**
303
+
304
+ ```typescript
305
+ import { SrpClientService } from './srp/srp-client-service.js';
306
+ import { SrpKeyDerivationService } from './srp/srp-key-derivation-service.js';
307
+ import { SrpGroup } from './srp/srp-group.js';
308
+ import { CryptoVersion } from './crypto/crypto-version.js';
309
+
310
+ const client = new SrpClientService();
311
+ const kdf = new SrpKeyDerivationService();
312
+
313
+ // 1. Вывести auth-hash из пароля
314
+ const authHash = await kdf.deriveAuthHashForSrp(
315
+ identity, password, salt, SrpGroup.Group2048, CryptoVersion.V1
316
+ );
317
+
318
+ // 2. Сгенерировать proof
319
+ const { A, M1, SessionKeyK } = await client.generateSrpProof(
320
+ identity,
321
+ authHash,
322
+ btoa(String.fromCharCode(...salt)),
323
+ btoa(String.fromCharCode(...session.publicKeyB)),
324
+ SrpGroup.Group2048
325
+ );
326
+
327
+ // Отправить серверу: A + M1
328
+ ```
329
+
330
+ **Сервер — проверка proof**
331
+
332
+ ```typescript
333
+ const serverM2 = await server.verifySrpProof(
334
+ session,
335
+ A,
336
+ M1,
337
+ SrpGroup.Group2048
338
+ );
339
+
340
+ // Отправить клиенту: serverM2
341
+ ```
342
+
343
+ **Клиент — проверка server proof**
344
+
345
+ ```typescript
346
+ const isValid = await client.verifyServerM2(
347
+ A,
348
+ M1,
349
+ SessionKeyK,
350
+ serverM2,
351
+ SrpGroup.Group2048
352
+ );
353
+ ```
354
+
355
+ ### Безопасность
356
+
357
+ - Все чувствительные буферы явно перезаписываются после использования
358
+ - Соль должна быть **минимум 16 байт**
359
+ - Ключ AES-256 — **строго 32 байта**
360
+ - SRP-группы защищены от атак на малые подгруппы (проверки `A % N != 0`, `B != 0`)
361
+ - Полностью опирается на нативный Web Crypto API — никаких самописных криптопримитивов
362
+
363
+ ### Лицензия
364
+
365
+ MIT