@omnituum/pqc-shared 0.2.6

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.
Files changed (67) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +543 -0
  3. package/dist/crypto/index.cjs +807 -0
  4. package/dist/crypto/index.d.cts +641 -0
  5. package/dist/crypto/index.d.ts +641 -0
  6. package/dist/crypto/index.js +716 -0
  7. package/dist/decrypt-eSHlbh1j.d.cts +321 -0
  8. package/dist/decrypt-eSHlbh1j.d.ts +321 -0
  9. package/dist/fs/index.cjs +1168 -0
  10. package/dist/fs/index.d.cts +400 -0
  11. package/dist/fs/index.d.ts +400 -0
  12. package/dist/fs/index.js +1091 -0
  13. package/dist/index.cjs +2160 -0
  14. package/dist/index.d.cts +282 -0
  15. package/dist/index.d.ts +282 -0
  16. package/dist/index.js +2031 -0
  17. package/dist/integrity-CCYjrap3.d.ts +31 -0
  18. package/dist/integrity-Dx9jukMH.d.cts +31 -0
  19. package/dist/types-61c7Q9ri.d.ts +134 -0
  20. package/dist/types-Ch0y-n7K.d.cts +134 -0
  21. package/dist/utils/index.cjs +129 -0
  22. package/dist/utils/index.d.cts +49 -0
  23. package/dist/utils/index.d.ts +49 -0
  24. package/dist/utils/index.js +114 -0
  25. package/dist/vault/index.cjs +713 -0
  26. package/dist/vault/index.d.cts +237 -0
  27. package/dist/vault/index.d.ts +237 -0
  28. package/dist/vault/index.js +677 -0
  29. package/dist/version-BygzPVGs.d.cts +55 -0
  30. package/dist/version-BygzPVGs.d.ts +55 -0
  31. package/package.json +86 -0
  32. package/src/crypto/dilithium.ts +233 -0
  33. package/src/crypto/hybrid.ts +358 -0
  34. package/src/crypto/index.ts +181 -0
  35. package/src/crypto/kyber.ts +199 -0
  36. package/src/crypto/nacl.ts +204 -0
  37. package/src/crypto/primitives/blake3.ts +141 -0
  38. package/src/crypto/primitives/chacha.ts +211 -0
  39. package/src/crypto/primitives/hkdf.ts +192 -0
  40. package/src/crypto/primitives/index.ts +54 -0
  41. package/src/crypto/primitives.ts +144 -0
  42. package/src/crypto/x25519.ts +134 -0
  43. package/src/fs/aes.ts +343 -0
  44. package/src/fs/argon2.ts +184 -0
  45. package/src/fs/browser.ts +408 -0
  46. package/src/fs/decrypt.ts +320 -0
  47. package/src/fs/encrypt.ts +324 -0
  48. package/src/fs/format.ts +425 -0
  49. package/src/fs/index.ts +144 -0
  50. package/src/fs/types.ts +304 -0
  51. package/src/index.ts +414 -0
  52. package/src/kdf/index.ts +311 -0
  53. package/src/runtime/crypto.ts +16 -0
  54. package/src/security/index.ts +345 -0
  55. package/src/tunnel/index.ts +39 -0
  56. package/src/tunnel/session.ts +229 -0
  57. package/src/tunnel/types.ts +115 -0
  58. package/src/utils/entropy.ts +128 -0
  59. package/src/utils/index.ts +25 -0
  60. package/src/utils/integrity.ts +95 -0
  61. package/src/vault/decrypt.ts +167 -0
  62. package/src/vault/encrypt.ts +207 -0
  63. package/src/vault/index.ts +71 -0
  64. package/src/vault/manager.ts +327 -0
  65. package/src/vault/migrate.ts +190 -0
  66. package/src/vault/types.ts +177 -0
  67. package/src/version.ts +304 -0
@@ -0,0 +1,327 @@
1
+ /**
2
+ * Omnituum PQC Shared - Vault Manager
3
+ *
4
+ * High-level operations for managing the PQC identity vault.
5
+ * Handles identity creation, rotation, import/export, and session management.
6
+ */
7
+
8
+ import type {
9
+ OmnituumVault,
10
+ HybridIdentityRecord,
11
+ VaultSettings,
12
+ VaultSession,
13
+ } from './types';
14
+ import { encryptVaultToBlob } from './encrypt';
15
+ import { decryptVaultFromFile } from './decrypt';
16
+ import { computeIntegrityHash } from '../utils/integrity';
17
+ import { generateId } from '../utils/entropy';
18
+ import { generateX25519Keypair, generateKyberKeypair, toHex } from '../crypto';
19
+ import { VAULT_VERSION } from '../version';
20
+
21
+ // ═══════════════════════════════════════════════════════════════════════════
22
+ // VAULT CREATION
23
+ // ═══════════════════════════════════════════════════════════════════════════
24
+
25
+ /**
26
+ * Create a new empty vault.
27
+ */
28
+ export function createEmptyVault(): OmnituumVault {
29
+ const now = new Date().toISOString();
30
+ return {
31
+ version: VAULT_VERSION,
32
+ identities: [],
33
+ settings: {
34
+ autoUnlock: false,
35
+ lockTimeout: 15,
36
+ showFingerprints: true,
37
+ },
38
+ integrityHash: computeIntegrityHash([]),
39
+ createdAt: now,
40
+ modifiedAt: now,
41
+ };
42
+ }
43
+
44
+ // ═══════════════════════════════════════════════════════════════════════════
45
+ // IDENTITY MANAGEMENT
46
+ // ═══════════════════════════════════════════════════════════════════════════
47
+
48
+ /**
49
+ * Create a new hybrid identity.
50
+ */
51
+ export async function createIdentity(name: string): Promise<HybridIdentityRecord | null> {
52
+ // Generate X25519 keypair
53
+ const x25519 = generateX25519Keypair();
54
+
55
+ // Generate Kyber keypair
56
+ const kyber = await generateKyberKeypair();
57
+ if (!kyber) {
58
+ console.error('Kyber key generation failed');
59
+ return null;
60
+ }
61
+
62
+ const now = new Date().toISOString();
63
+ const deviceFingerprint = await getDeviceFingerprint();
64
+
65
+ return {
66
+ id: generateId(),
67
+ name,
68
+ x25519PubHex: x25519.publicHex,
69
+ x25519SecHex: x25519.secretHex,
70
+ kyberPubB64: kyber.publicB64,
71
+ kyberSecB64: kyber.secretB64,
72
+ createdAt: now,
73
+ rotationCount: 0,
74
+ deviceFingerprint,
75
+ };
76
+ }
77
+
78
+ /**
79
+ * Add an identity to the vault.
80
+ */
81
+ export function addIdentity(vault: OmnituumVault, identity: HybridIdentityRecord): OmnituumVault {
82
+ const identities = [...vault.identities, identity];
83
+ return {
84
+ ...vault,
85
+ identities,
86
+ integrityHash: computeIntegrityHash(identities),
87
+ modifiedAt: new Date().toISOString(),
88
+ };
89
+ }
90
+
91
+ /**
92
+ * Remove an identity from the vault.
93
+ */
94
+ export function removeIdentity(vault: OmnituumVault, identityId: string): OmnituumVault {
95
+ const identities = vault.identities.filter(i => i.id !== identityId);
96
+ return {
97
+ ...vault,
98
+ identities,
99
+ integrityHash: computeIntegrityHash(identities),
100
+ modifiedAt: new Date().toISOString(),
101
+ settings: {
102
+ ...vault.settings,
103
+ lastUsedIdentity: vault.settings.lastUsedIdentity === identityId
104
+ ? undefined
105
+ : vault.settings.lastUsedIdentity,
106
+ },
107
+ };
108
+ }
109
+
110
+ /**
111
+ * Rotate keys for an identity (regenerate Kyber + X25519).
112
+ */
113
+ export async function rotateIdentityKeys(
114
+ vault: OmnituumVault,
115
+ identityId: string
116
+ ): Promise<OmnituumVault | null> {
117
+ const index = vault.identities.findIndex(i => i.id === identityId);
118
+ if (index === -1) return null;
119
+
120
+ const existing = vault.identities[index];
121
+
122
+ // Generate new X25519 keypair
123
+ const x25519 = generateX25519Keypair();
124
+
125
+ // Generate new Kyber keypair
126
+ const kyber = await generateKyberKeypair();
127
+ if (!kyber) return null;
128
+
129
+ const now = new Date().toISOString();
130
+
131
+ const updated: HybridIdentityRecord = {
132
+ ...existing,
133
+ x25519PubHex: x25519.publicHex,
134
+ x25519SecHex: x25519.secretHex,
135
+ kyberPubB64: kyber.publicB64,
136
+ kyberSecB64: kyber.secretB64,
137
+ lastRotatedAt: now,
138
+ rotationCount: existing.rotationCount + 1,
139
+ };
140
+
141
+ const identities = [...vault.identities];
142
+ identities[index] = updated;
143
+
144
+ return {
145
+ ...vault,
146
+ identities,
147
+ integrityHash: computeIntegrityHash(identities),
148
+ modifiedAt: now,
149
+ };
150
+ }
151
+
152
+ /**
153
+ * Update identity metadata.
154
+ */
155
+ export function updateIdentityMetadata(
156
+ vault: OmnituumVault,
157
+ identityId: string,
158
+ updates: Partial<Pick<HybridIdentityRecord, 'name' | 'metadata'>>
159
+ ): OmnituumVault {
160
+ const identities = vault.identities.map(i =>
161
+ i.id === identityId ? { ...i, ...updates } : i
162
+ );
163
+ return {
164
+ ...vault,
165
+ identities,
166
+ integrityHash: computeIntegrityHash(identities),
167
+ modifiedAt: new Date().toISOString(),
168
+ };
169
+ }
170
+
171
+ // ═══════════════════════════════════════════════════════════════════════════
172
+ // VAULT SETTINGS
173
+ // ═══════════════════════════════════════════════════════════════════════════
174
+
175
+ /**
176
+ * Update vault settings.
177
+ */
178
+ export function updateSettings(
179
+ vault: OmnituumVault,
180
+ settings: Partial<VaultSettings>
181
+ ): OmnituumVault {
182
+ return {
183
+ ...vault,
184
+ settings: { ...vault.settings, ...settings },
185
+ modifiedAt: new Date().toISOString(),
186
+ };
187
+ }
188
+
189
+ /**
190
+ * Set the active identity.
191
+ */
192
+ export function setActiveIdentity(vault: OmnituumVault, identityId: string): OmnituumVault {
193
+ return updateSettings(vault, { lastUsedIdentity: identityId });
194
+ }
195
+
196
+ // ═══════════════════════════════════════════════════════════════════════════
197
+ // IMPORT / EXPORT
198
+ // ═══════════════════════════════════════════════════════════════════════════
199
+
200
+ /**
201
+ * Export vault to encrypted file.
202
+ */
203
+ export async function exportVault(vault: OmnituumVault, password: string): Promise<Blob> {
204
+ return encryptVaultToBlob(vault, password);
205
+ }
206
+
207
+ /**
208
+ * Import vault from encrypted file.
209
+ */
210
+ export async function importVault(file: File, password: string): Promise<OmnituumVault> {
211
+ return decryptVaultFromFile(file, password);
212
+ }
213
+
214
+ /**
215
+ * Trigger download of encrypted vault.
216
+ */
217
+ export async function downloadVault(vault: OmnituumVault, password: string): Promise<void> {
218
+ const blob = await exportVault(vault, password);
219
+ const url = URL.createObjectURL(blob);
220
+ const a = document.createElement('a');
221
+ a.href = url;
222
+ a.download = `omnituum_vault_${new Date().toISOString().split('T')[0]}.enc`;
223
+ document.body.appendChild(a);
224
+ a.click();
225
+ document.body.removeChild(a);
226
+ URL.revokeObjectURL(url);
227
+ }
228
+
229
+ // ═══════════════════════════════════════════════════════════════════════════
230
+ // SESSION MANAGEMENT
231
+ // ═══════════════════════════════════════════════════════════════════════════
232
+
233
+ let currentSession: VaultSession = {
234
+ unlocked: false,
235
+ sessionKey: null,
236
+ unlockedAt: null,
237
+ activeIdentityId: null,
238
+ };
239
+
240
+ /**
241
+ * Get current session state.
242
+ */
243
+ export function getSession(): VaultSession {
244
+ return { ...currentSession };
245
+ }
246
+
247
+ /**
248
+ * Unlock vault and store session key in memory.
249
+ */
250
+ export async function unlockSession(password: string, vault: OmnituumVault): Promise<boolean> {
251
+ try {
252
+ // Verify password by attempting to encrypt/decrypt
253
+ const salt = globalThis.crypto.getRandomValues(new Uint8Array(32));
254
+ const passwordKey = await globalThis.crypto.subtle.importKey(
255
+ 'raw',
256
+ new TextEncoder().encode(password),
257
+ 'PBKDF2',
258
+ false,
259
+ ['deriveBits', 'deriveKey']
260
+ );
261
+
262
+ const sessionKey = await globalThis.crypto.subtle.deriveKey(
263
+ {
264
+ name: 'PBKDF2',
265
+ salt,
266
+ iterations: 100000, // Faster for session key
267
+ hash: 'SHA-256',
268
+ },
269
+ passwordKey,
270
+ { name: 'AES-GCM', length: 256 },
271
+ false,
272
+ ['encrypt', 'decrypt']
273
+ );
274
+
275
+ currentSession = {
276
+ unlocked: true,
277
+ sessionKey,
278
+ unlockedAt: Date.now(),
279
+ activeIdentityId: vault.settings.lastUsedIdentity || vault.identities[0]?.id || null,
280
+ };
281
+
282
+ return true;
283
+ } catch {
284
+ return false;
285
+ }
286
+ }
287
+
288
+ /**
289
+ * Lock the session.
290
+ */
291
+ export function lockSession(): void {
292
+ currentSession = {
293
+ unlocked: false,
294
+ sessionKey: null,
295
+ unlockedAt: null,
296
+ activeIdentityId: null,
297
+ };
298
+ }
299
+
300
+ /**
301
+ * Set active identity in session.
302
+ */
303
+ export function setSessionActiveIdentity(identityId: string): void {
304
+ if (currentSession.unlocked) {
305
+ currentSession.activeIdentityId = identityId;
306
+ }
307
+ }
308
+
309
+ // ═══════════════════════════════════════════════════════════════════════════
310
+ // DEVICE FINGERPRINT
311
+ // ═══════════════════════════════════════════════════════════════════════════
312
+
313
+ /**
314
+ * Generate a device fingerprint for identity tracking.
315
+ */
316
+ async function getDeviceFingerprint(): Promise<string> {
317
+ const data = [
318
+ navigator.userAgent,
319
+ navigator.language,
320
+ screen.width,
321
+ screen.height,
322
+ new Date().getTimezoneOffset(),
323
+ ].join('|');
324
+
325
+ const hash = await globalThis.crypto.subtle.digest('SHA-256', new TextEncoder().encode(data));
326
+ return toHex(new Uint8Array(hash)).slice(0, 16);
327
+ }
@@ -0,0 +1,190 @@
1
+ /**
2
+ * Omnituum PQC Shared - Vault Migration
3
+ *
4
+ * One-way migration from v1 (PBKDF2) to v2 (Argon2id) encrypted vaults.
5
+ * Includes memory hygiene for sensitive data.
6
+ */
7
+
8
+ import type {
9
+ OmnituumVault,
10
+ EncryptedVaultFile,
11
+ EncryptedVaultFileV1,
12
+ EncryptedVaultFileV2,
13
+ } from './types';
14
+ import { decryptVault } from './decrypt';
15
+ import { encryptVaultV2 } from './encrypt';
16
+ import { zeroMemory } from '../security';
17
+ import {
18
+ VAULT_ENCRYPTED_VERSION,
19
+ VAULT_ENCRYPTED_VERSION_V2,
20
+ } from '../version';
21
+
22
+ // ═══════════════════════════════════════════════════════════════════════════
23
+ // MIGRATION TYPES
24
+ // ═══════════════════════════════════════════════════════════════════════════
25
+
26
+ export interface MigrationOptions {
27
+ /** Source encrypted vault */
28
+ encryptedVault: EncryptedVaultFile;
29
+ /** Vault password */
30
+ password: string;
31
+ /** Keep backup of original vault data (default: false) */
32
+ keepBackup?: boolean;
33
+ }
34
+
35
+ export interface MigrationResult {
36
+ /** New v2 encrypted vault */
37
+ encryptedVault: EncryptedVaultFileV2;
38
+ /** Original vault (only if keepBackup was true) */
39
+ backup?: EncryptedVaultFile;
40
+ /** Source version */
41
+ sourceVersion: string;
42
+ /** Target version */
43
+ targetVersion: string;
44
+ /** Migration timestamp */
45
+ migratedAt: string;
46
+ }
47
+
48
+ // ═══════════════════════════════════════════════════════════════════════════
49
+ // VERSION DETECTION
50
+ // ═══════════════════════════════════════════════════════════════════════════
51
+
52
+ /**
53
+ * Check if vault needs migration (is v1 format).
54
+ */
55
+ export function needsMigration(encryptedVault: EncryptedVaultFile): boolean {
56
+ return encryptedVault.version === VAULT_ENCRYPTED_VERSION;
57
+ }
58
+
59
+ /**
60
+ * Check if vault is already v2 format.
61
+ */
62
+ export function isV2Vault(encryptedVault: EncryptedVaultFile): boolean {
63
+ return encryptedVault.version === VAULT_ENCRYPTED_VERSION_V2;
64
+ }
65
+
66
+ /**
67
+ * Get vault KDF info for display.
68
+ */
69
+ export function getVaultKdfInfo(encryptedVault: EncryptedVaultFile): {
70
+ kdf: string;
71
+ version: string;
72
+ isSecure: boolean;
73
+ recommendation?: string;
74
+ } {
75
+ if (encryptedVault.version === VAULT_ENCRYPTED_VERSION_V2) {
76
+ const v2 = encryptedVault as EncryptedVaultFileV2;
77
+ return {
78
+ kdf: `Argon2id (${v2.memoryCost / 1024}MB, ${v2.timeCost} iterations)`,
79
+ version: 'v2',
80
+ isSecure: true,
81
+ };
82
+ } else {
83
+ const v1 = encryptedVault as EncryptedVaultFileV1;
84
+ return {
85
+ kdf: `PBKDF2-SHA256 (${v1.iterations.toLocaleString()} iterations)`,
86
+ version: 'v1',
87
+ isSecure: true, // Still secure, just not as modern
88
+ recommendation: 'Consider upgrading to Argon2id for stronger protection',
89
+ };
90
+ }
91
+ }
92
+
93
+ // ═══════════════════════════════════════════════════════════════════════════
94
+ // MIGRATION
95
+ // ═══════════════════════════════════════════════════════════════════════════
96
+
97
+ /**
98
+ * Migrate an encrypted vault from v1 (PBKDF2) to v2 (Argon2id).
99
+ *
100
+ * This is a ONE-WAY migration. The original vault remains unchanged,
101
+ * but a new v2 encrypted vault is returned.
102
+ *
103
+ * Memory hygiene: Sensitive data (decrypted vault) is zeroed after use.
104
+ *
105
+ * @param options - Migration options
106
+ * @returns Migration result with new v2 vault
107
+ * @throws Error if decryption fails or vault is already v2
108
+ */
109
+ export async function migrateEncryptedVault(
110
+ options: MigrationOptions
111
+ ): Promise<MigrationResult> {
112
+ const { encryptedVault, password, keepBackup = false } = options;
113
+
114
+ // Check if already v2
115
+ if (isV2Vault(encryptedVault)) {
116
+ throw new Error('Vault is already v2 format, no migration needed');
117
+ }
118
+
119
+ // Track sensitive data for cleanup
120
+ let decryptedVaultJson: Uint8Array | null = null;
121
+
122
+ try {
123
+ // Decrypt the vault
124
+ const vault = await decryptVault(encryptedVault, password);
125
+
126
+ // Serialize for memory tracking (so we can zero it)
127
+ const vaultJson = JSON.stringify(vault);
128
+ decryptedVaultJson = new TextEncoder().encode(vaultJson);
129
+
130
+ // Re-encrypt with v2 (Argon2id)
131
+ const newEncryptedVault = await encryptVaultV2(vault, password);
132
+
133
+ return {
134
+ encryptedVault: newEncryptedVault,
135
+ backup: keepBackup ? encryptedVault : undefined,
136
+ sourceVersion: encryptedVault.version,
137
+ targetVersion: VAULT_ENCRYPTED_VERSION_V2,
138
+ migratedAt: new Date().toISOString(),
139
+ };
140
+ } finally {
141
+ // Zero sensitive data
142
+ if (decryptedVaultJson) {
143
+ zeroMemory(decryptedVaultJson);
144
+ }
145
+ }
146
+ }
147
+
148
+ /**
149
+ * Validate migration by decrypting both versions and comparing.
150
+ * Used for testing migration integrity.
151
+ *
152
+ * @param original - Original encrypted vault
153
+ * @param migrated - Migrated encrypted vault
154
+ * @param password - Vault password
155
+ * @returns true if vaults contain identical data
156
+ */
157
+ export async function validateMigration(
158
+ original: EncryptedVaultFile,
159
+ migrated: EncryptedVaultFileV2,
160
+ password: string
161
+ ): Promise<boolean> {
162
+ let originalVaultJson: Uint8Array | null = null;
163
+ let migratedVaultJson: Uint8Array | null = null;
164
+
165
+ try {
166
+ const originalVault = await decryptVault(original, password);
167
+ const migratedVault = await decryptVault(migrated, password);
168
+
169
+ // Serialize for comparison
170
+ originalVaultJson = new TextEncoder().encode(JSON.stringify(originalVault));
171
+ migratedVaultJson = new TextEncoder().encode(JSON.stringify(migratedVault));
172
+
173
+ // Compare serialized JSON
174
+ if (originalVaultJson.length !== migratedVaultJson.length) {
175
+ return false;
176
+ }
177
+
178
+ for (let i = 0; i < originalVaultJson.length; i++) {
179
+ if (originalVaultJson[i] !== migratedVaultJson[i]) {
180
+ return false;
181
+ }
182
+ }
183
+
184
+ return true;
185
+ } finally {
186
+ // Zero sensitive data
187
+ if (originalVaultJson) zeroMemory(originalVaultJson);
188
+ if (migratedVaultJson) zeroMemory(migratedVaultJson);
189
+ }
190
+ }
@@ -0,0 +1,177 @@
1
+ /**
2
+ * Omnituum PQC Shared - Vault Types
3
+ *
4
+ * Type definitions for the PQC identity vault.
5
+ * FROZEN CONTRACTS - see pqc-docs/specs/vault.v1.md
6
+ */
7
+
8
+ import type {
9
+ VAULT_VERSION,
10
+ VAULT_ENCRYPTED_VERSION,
11
+ VAULT_ENCRYPTED_VERSION_V2,
12
+ VAULT_KDF,
13
+ VAULT_KDF_V2,
14
+ VAULT_ALGORITHM,
15
+ } from '../version';
16
+
17
+ // ═══════════════════════════════════════════════════════════════════════════
18
+ // IDENTITY TYPES
19
+ // ═══════════════════════════════════════════════════════════════════════════
20
+
21
+ export interface HybridIdentityRecord {
22
+ /** Unique identity ID */
23
+ id: string;
24
+ /** Display name */
25
+ name: string;
26
+ /** X25519 public key (hex) */
27
+ x25519PubHex: string;
28
+ /** X25519 secret key (hex) - encrypted in vault */
29
+ x25519SecHex: string;
30
+ /** Kyber public key (base64) */
31
+ kyberPubB64: string;
32
+ /** Kyber secret key (base64) - encrypted in vault */
33
+ kyberSecB64: string;
34
+ /** Creation timestamp */
35
+ createdAt: string;
36
+ /** Last rotation timestamp */
37
+ lastRotatedAt?: string;
38
+ /** Device fingerprint */
39
+ deviceFingerprint?: string;
40
+ /** Key rotation count */
41
+ rotationCount: number;
42
+ /** Identity metadata */
43
+ metadata?: {
44
+ label?: string;
45
+ notes?: string;
46
+ tags?: string[];
47
+ };
48
+ }
49
+
50
+ // ═══════════════════════════════════════════════════════════════════════════
51
+ // VAULT TYPES
52
+ // ═══════════════════════════════════════════════════════════════════════════
53
+
54
+ export interface VaultSettings {
55
+ /** Auto-unlock on return (session memory) */
56
+ autoUnlock: boolean;
57
+ /** Last used identity ID */
58
+ lastUsedIdentity?: string;
59
+ /** Lock timeout in minutes (0 = never auto-lock) */
60
+ lockTimeout: number;
61
+ /** Show key fingerprints in UI */
62
+ showFingerprints: boolean;
63
+ }
64
+
65
+ export interface OmnituumVault {
66
+ /** Vault format version (FROZEN - see pqc-docs/specs/vault.v1.md) */
67
+ version: typeof VAULT_VERSION;
68
+ /** Stored identities */
69
+ identities: HybridIdentityRecord[];
70
+ /** Vault settings */
71
+ settings: VaultSettings;
72
+ /** SHA-256 hash of serialized identities (integrity check) */
73
+ integrityHash: string;
74
+ /** Vault creation timestamp */
75
+ createdAt: string;
76
+ /** Last modified timestamp */
77
+ modifiedAt: string;
78
+ }
79
+
80
+ // ═══════════════════════════════════════════════════════════════════════════
81
+ // ENCRYPTED VAULT TYPES
82
+ // ═══════════════════════════════════════════════════════════════════════════
83
+
84
+ /** V1 encrypted vault (PBKDF2) */
85
+ export interface EncryptedVaultFileV1 {
86
+ /** File format version (FROZEN - see pqc-docs/specs/vault.v1.md) */
87
+ version: typeof VAULT_ENCRYPTED_VERSION;
88
+ /** Key derivation function */
89
+ kdf: typeof VAULT_KDF;
90
+ /** PBKDF2 iterations */
91
+ iterations: number;
92
+ /** Salt (base64) */
93
+ salt: string;
94
+ /** AES-GCM IV (base64) */
95
+ iv: string;
96
+ /** Encrypted vault (base64) */
97
+ ciphertext: string;
98
+ /** Auth tag included in ciphertext (AES-GCM) */
99
+ algorithm: typeof VAULT_ALGORITHM;
100
+ }
101
+
102
+ /** V2 encrypted vault (Argon2id) */
103
+ export interface EncryptedVaultFileV2 {
104
+ /** File format version */
105
+ version: typeof VAULT_ENCRYPTED_VERSION_V2;
106
+ /** Key derivation function */
107
+ kdf: typeof VAULT_KDF_V2;
108
+ /** Argon2id memory cost (KiB) */
109
+ memoryCost: number;
110
+ /** Argon2id time cost (iterations) */
111
+ timeCost: number;
112
+ /** Argon2id parallelism */
113
+ parallelism: number;
114
+ /** Salt (base64) */
115
+ salt: string;
116
+ /** AES-GCM IV (base64) */
117
+ iv: string;
118
+ /** Encrypted vault (base64) */
119
+ ciphertext: string;
120
+ /** Auth tag included in ciphertext (AES-GCM) */
121
+ algorithm: typeof VAULT_ALGORITHM;
122
+ }
123
+
124
+ /** Union type for any encrypted vault version */
125
+ export type EncryptedVaultFile = EncryptedVaultFileV1 | EncryptedVaultFileV2;
126
+
127
+ // ═══════════════════════════════════════════════════════════════════════════
128
+ // HEALTH CHECK TYPES
129
+ // ═══════════════════════════════════════════════════════════════════════════
130
+
131
+ export type HealthStatus = 'healthy' | 'needs-rotation' | 'warning' | 'error';
132
+
133
+ export interface IdentityHealth {
134
+ /** Overall health status */
135
+ status: HealthStatus;
136
+ /** Entropy score (0-100) */
137
+ entropyScore: number;
138
+ /** Integrity verified */
139
+ integrityValid: boolean;
140
+ /** SHA-256 fingerprint */
141
+ fingerprint: string;
142
+ /** Days since last rotation */
143
+ daysSinceRotation: number;
144
+ /** Kyber key valid */
145
+ kyberValid: boolean;
146
+ /** X25519 key valid */
147
+ x25519Valid: boolean;
148
+ /** Recommendations */
149
+ recommendations: string[];
150
+ }
151
+
152
+ // ═══════════════════════════════════════════════════════════════════════════
153
+ // SESSION TYPES
154
+ // ═══════════════════════════════════════════════════════════════════════════
155
+
156
+ export interface VaultSession {
157
+ /** Session active */
158
+ unlocked: boolean;
159
+ /** Derived encryption key (in memory only) */
160
+ sessionKey: CryptoKey | null;
161
+ /** Unlock timestamp */
162
+ unlockedAt: number | null;
163
+ /** Active identity ID */
164
+ activeIdentityId: string | null;
165
+ }
166
+
167
+ // ═══════════════════════════════════════════════════════════════════════════
168
+ // DEFAULT VALUES
169
+ // ═══════════════════════════════════════════════════════════════════════════
170
+
171
+ export const DEFAULT_VAULT_SETTINGS: VaultSettings = {
172
+ autoUnlock: false,
173
+ lockTimeout: 15,
174
+ showFingerprints: true,
175
+ };
176
+
177
+ export const PBKDF2_ITERATIONS = 600000; // OWASP 2023 recommendation