@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,167 @@
1
+ /**
2
+ * Omnituum PQC Shared - Vault Decryption
3
+ *
4
+ * Password-based decryption using PBKDF2 or Argon2id + AES-256-GCM.
5
+ * Includes integrity verification.
6
+ */
7
+
8
+ import type { OmnituumVault, EncryptedVaultFile, EncryptedVaultFileV2 } from './types';
9
+ import { deriveKey } from './encrypt';
10
+ import { fromB64 } from '../crypto/primitives';
11
+ import {
12
+ assertVaultEncryptedVersion,
13
+ assertVaultVersion,
14
+ VAULT_VERSION,
15
+ VAULT_ENCRYPTED_VERSION,
16
+ VAULT_ENCRYPTED_VERSION_V2,
17
+ VAULT_KDF,
18
+ VAULT_ALGORITHM,
19
+ } from '../version';
20
+ import { kdfDeriveKey, configFromParams } from '../kdf';
21
+
22
+ // ═══════════════════════════════════════════════════════════════════════════
23
+ // TEXT ENCODING
24
+ // ═══════════════════════════════════════════════════════════════════════════
25
+
26
+ const textDecoder = new TextDecoder();
27
+
28
+ // ═══════════════════════════════════════════════════════════════════════════
29
+ // VAULT DECRYPTION
30
+ // ═══════════════════════════════════════════════════════════════════════════
31
+
32
+ /**
33
+ * Decrypt an encrypted vault file with a password.
34
+ * Supports both v1 (PBKDF2) and v2 (Argon2id) formats.
35
+ *
36
+ * @param encryptedFile - Encrypted vault file structure
37
+ * @param password - User password
38
+ * @returns Decrypted vault
39
+ * @throws Error if decryption fails (wrong password or corrupted data)
40
+ */
41
+ export async function decryptVault(
42
+ encryptedFile: EncryptedVaultFile,
43
+ password: string
44
+ ): Promise<OmnituumVault> {
45
+ // Validate encrypted file version (throws VersionMismatchError if unsupported)
46
+ assertVaultEncryptedVersion(encryptedFile.version);
47
+
48
+ // Decode base64 values
49
+ const salt = fromB64(encryptedFile.salt);
50
+ const iv = fromB64(encryptedFile.iv);
51
+ const ciphertext = fromB64(encryptedFile.ciphertext);
52
+
53
+ // Derive decryption key based on version
54
+ let key: CryptoKey;
55
+
56
+ if (encryptedFile.version === VAULT_ENCRYPTED_VERSION_V2) {
57
+ // V2: Argon2id
58
+ const v2File = encryptedFile as EncryptedVaultFileV2;
59
+ const kdfConfig = configFromParams('Argon2id', {
60
+ memoryCost: v2File.memoryCost,
61
+ timeCost: v2File.timeCost,
62
+ parallelism: v2File.parallelism,
63
+ });
64
+ const keyBytes = await kdfDeriveKey(password, salt, kdfConfig);
65
+ // Create ArrayBuffer for importKey compatibility
66
+ const keyBuffer = new ArrayBuffer(keyBytes.length);
67
+ new Uint8Array(keyBuffer).set(keyBytes);
68
+ key = await globalThis.crypto.subtle.importKey(
69
+ 'raw',
70
+ keyBuffer,
71
+ { name: 'AES-GCM', length: 256 },
72
+ false,
73
+ ['decrypt']
74
+ );
75
+ } else {
76
+ // V1: PBKDF2
77
+ key = await deriveKey(password, salt, (encryptedFile as any).iterations);
78
+ }
79
+
80
+ try {
81
+ // Create clean ArrayBuffers to ensure type compatibility
82
+ const ivArrayBuffer = new ArrayBuffer(iv.length);
83
+ new Uint8Array(ivArrayBuffer).set(iv);
84
+ const ciphertextArrayBuffer = new ArrayBuffer(ciphertext.length);
85
+ new Uint8Array(ciphertextArrayBuffer).set(ciphertext);
86
+
87
+ // Decrypt with AES-256-GCM
88
+ const plaintext = await globalThis.crypto.subtle.decrypt(
89
+ { name: 'AES-GCM', iv: ivArrayBuffer },
90
+ key,
91
+ ciphertextArrayBuffer
92
+ );
93
+
94
+ // Parse JSON
95
+ const json = textDecoder.decode(plaintext);
96
+ const vault = JSON.parse(json) as OmnituumVault;
97
+
98
+ // Validate vault version (throws VersionMismatchError if unsupported)
99
+ assertVaultVersion(vault.version);
100
+
101
+ // Validate structure
102
+ if (!Array.isArray(vault.identities)) {
103
+ throw new Error('Invalid vault structure: missing identities array');
104
+ }
105
+
106
+ return vault;
107
+ } catch (error) {
108
+ // AES-GCM will throw if authentication fails (wrong password)
109
+ if (error instanceof DOMException && error.name === 'OperationError') {
110
+ throw new Error('Incorrect password or corrupted vault');
111
+ }
112
+ throw error;
113
+ }
114
+ }
115
+
116
+ /**
117
+ * Decrypt a vault from a JSON string.
118
+ *
119
+ * @param json - Encrypted vault JSON string
120
+ * @param password - User password
121
+ * @returns Decrypted vault
122
+ */
123
+ export async function decryptVaultFromJson(
124
+ json: string,
125
+ password: string
126
+ ): Promise<OmnituumVault> {
127
+ const encryptedFile = JSON.parse(json) as EncryptedVaultFile;
128
+ return decryptVault(encryptedFile, password);
129
+ }
130
+
131
+ /**
132
+ * Decrypt a vault from a File object.
133
+ *
134
+ * @param file - File object (from file input)
135
+ * @param password - User password
136
+ * @returns Decrypted vault
137
+ */
138
+ export async function decryptVaultFromFile(
139
+ file: File,
140
+ password: string
141
+ ): Promise<OmnituumVault> {
142
+ const text = await file.text();
143
+ return decryptVaultFromJson(text, password);
144
+ }
145
+
146
+ /**
147
+ * Validate an encrypted vault file without decrypting.
148
+ *
149
+ * @param json - JSON string to validate
150
+ * @returns true if valid encrypted vault file structure
151
+ */
152
+ export function isValidEncryptedVaultFile(json: string): boolean {
153
+ try {
154
+ const parsed = JSON.parse(json);
155
+ return (
156
+ parsed.version === VAULT_ENCRYPTED_VERSION &&
157
+ parsed.kdf === VAULT_KDF &&
158
+ typeof parsed.iterations === 'number' &&
159
+ typeof parsed.salt === 'string' &&
160
+ typeof parsed.iv === 'string' &&
161
+ typeof parsed.ciphertext === 'string' &&
162
+ parsed.algorithm === VAULT_ALGORITHM
163
+ );
164
+ } catch {
165
+ return false;
166
+ }
167
+ }
@@ -0,0 +1,207 @@
1
+ /**
2
+ * Omnituum PQC Shared - Vault Encryption
3
+ *
4
+ * Password-based encryption using PBKDF2 or Argon2id + AES-256-GCM.
5
+ * All operations use the Web Crypto API for browser compatibility.
6
+ */
7
+
8
+ import type { OmnituumVault, EncryptedVaultFile, EncryptedVaultFileV1, EncryptedVaultFileV2 } from './types';
9
+ import { PBKDF2_ITERATIONS } from './types';
10
+ import { toB64 } from '../crypto/primitives';
11
+ import {
12
+ VAULT_ENCRYPTED_VERSION,
13
+ VAULT_ENCRYPTED_VERSION_V2,
14
+ VAULT_KDF,
15
+ VAULT_KDF_V2,
16
+ VAULT_ALGORITHM,
17
+ } from '../version';
18
+ import { kdfDeriveKey, KDF_CONFIG_ARGON2ID } from '../kdf';
19
+
20
+ // ═══════════════════════════════════════════════════════════════════════════
21
+ // TEXT ENCODING
22
+ // ═══════════════════════════════════════════════════════════════════════════
23
+
24
+ const textEncoder = new TextEncoder();
25
+
26
+ // ═══════════════════════════════════════════════════════════════════════════
27
+ // KEY DERIVATION
28
+ // ═══════════════════════════════════════════════════════════════════════════
29
+
30
+ /**
31
+ * Derive an AES-256 key from a password using PBKDF2-SHA256.
32
+ *
33
+ * @param password - User password
34
+ * @param salt - 32-byte salt
35
+ * @param iterations - PBKDF2 iterations (default: 600,000)
36
+ * @returns CryptoKey for AES-GCM
37
+ */
38
+ export async function deriveKey(
39
+ password: string,
40
+ salt: Uint8Array,
41
+ iterations: number = PBKDF2_ITERATIONS
42
+ ): Promise<CryptoKey> {
43
+ // Import password as raw key material
44
+ const passwordKey = await globalThis.crypto.subtle.importKey(
45
+ 'raw',
46
+ textEncoder.encode(password),
47
+ 'PBKDF2',
48
+ false,
49
+ ['deriveBits', 'deriveKey']
50
+ );
51
+
52
+ // Derive AES-256-GCM key
53
+ // Create a clean ArrayBuffer to ensure type compatibility
54
+ const saltArrayBuffer = new ArrayBuffer(salt.length);
55
+ new Uint8Array(saltArrayBuffer).set(salt);
56
+ return globalThis.crypto.subtle.deriveKey(
57
+ {
58
+ name: 'PBKDF2',
59
+ salt: saltArrayBuffer,
60
+ iterations,
61
+ hash: 'SHA-256',
62
+ },
63
+ passwordKey,
64
+ { name: 'AES-GCM', length: 256 },
65
+ false, // not extractable
66
+ ['encrypt', 'decrypt']
67
+ );
68
+ }
69
+
70
+ // ═══════════════════════════════════════════════════════════════════════════
71
+ // VAULT ENCRYPTION
72
+ // ═══════════════════════════════════════════════════════════════════════════
73
+
74
+ /**
75
+ * Encrypt a vault with a password.
76
+ *
77
+ * Uses PBKDF2-SHA256 for key derivation and AES-256-GCM for encryption.
78
+ * The salt and IV are randomly generated and included in the output.
79
+ *
80
+ * @param vault - Vault to encrypt
81
+ * @param password - User password
82
+ * @returns Encrypted vault file structure
83
+ */
84
+ export async function encryptVault(
85
+ vault: OmnituumVault,
86
+ password: string
87
+ ): Promise<EncryptedVaultFile> {
88
+ // Generate random salt (32 bytes) and IV (12 bytes for GCM)
89
+ const salt = globalThis.crypto.getRandomValues(new Uint8Array(32));
90
+ const iv = globalThis.crypto.getRandomValues(new Uint8Array(12));
91
+
92
+ // Derive encryption key
93
+ const key = await deriveKey(password, salt);
94
+
95
+ // Serialize vault to JSON
96
+ const plaintext = textEncoder.encode(JSON.stringify(vault));
97
+
98
+ // Encrypt with AES-256-GCM
99
+ const ciphertext = await globalThis.crypto.subtle.encrypt(
100
+ { name: 'AES-GCM', iv },
101
+ key,
102
+ plaintext
103
+ );
104
+
105
+ return {
106
+ version: VAULT_ENCRYPTED_VERSION,
107
+ kdf: VAULT_KDF,
108
+ iterations: PBKDF2_ITERATIONS,
109
+ salt: toB64(salt),
110
+ iv: toB64(iv),
111
+ ciphertext: toB64(new Uint8Array(ciphertext)),
112
+ algorithm: VAULT_ALGORITHM,
113
+ };
114
+ }
115
+
116
+ /**
117
+ * Encrypt vault to a downloadable blob.
118
+ *
119
+ * @param vault - Vault to encrypt
120
+ * @param password - User password
121
+ * @returns Blob for download
122
+ */
123
+ export async function encryptVaultToBlob(
124
+ vault: OmnituumVault,
125
+ password: string
126
+ ): Promise<Blob> {
127
+ const encrypted = await encryptVault(vault, password);
128
+ const json = JSON.stringify(encrypted, null, 2);
129
+ return new Blob([json], { type: 'application/json' });
130
+ }
131
+
132
+ /**
133
+ * Encrypt vault to a data URL for download.
134
+ *
135
+ * @param vault - Vault to encrypt
136
+ * @param password - User password
137
+ * @returns Data URL
138
+ */
139
+ export async function encryptVaultToDataURL(
140
+ vault: OmnituumVault,
141
+ password: string
142
+ ): Promise<string> {
143
+ const encrypted = await encryptVault(vault, password);
144
+ const json = JSON.stringify(encrypted, null, 2);
145
+ return 'data:application/json;charset=utf-8,' + encodeURIComponent(json);
146
+ }
147
+
148
+ // ═══════════════════════════════════════════════════════════════════════════
149
+ // V2 ENCRYPTION (ARGON2ID)
150
+ // ═══════════════════════════════════════════════════════════════════════════
151
+
152
+ /**
153
+ * Encrypt a vault with a password using Argon2id (v2 format).
154
+ *
155
+ * Uses Argon2id for key derivation (64MB memory, 3 iterations) and AES-256-GCM.
156
+ * This is the recommended format for new vaults.
157
+ *
158
+ * @param vault - Vault to encrypt
159
+ * @param password - User password
160
+ * @returns Encrypted vault file structure (v2)
161
+ */
162
+ export async function encryptVaultV2(
163
+ vault: OmnituumVault,
164
+ password: string
165
+ ): Promise<EncryptedVaultFileV2> {
166
+ // Generate random salt (32 bytes) and IV (12 bytes for GCM)
167
+ const salt = globalThis.crypto.getRandomValues(new Uint8Array(32));
168
+ const iv = globalThis.crypto.getRandomValues(new Uint8Array(12));
169
+
170
+ // Derive key using Argon2id
171
+ const keyBytes = await kdfDeriveKey(password, salt, KDF_CONFIG_ARGON2ID);
172
+
173
+ // Create ArrayBuffer from key bytes for importKey compatibility
174
+ const keyBuffer = new ArrayBuffer(keyBytes.length);
175
+ new Uint8Array(keyBuffer).set(keyBytes);
176
+
177
+ // Import key for AES-GCM
178
+ const key = await globalThis.crypto.subtle.importKey(
179
+ 'raw',
180
+ keyBuffer,
181
+ { name: 'AES-GCM', length: 256 },
182
+ false,
183
+ ['encrypt']
184
+ );
185
+
186
+ // Serialize vault to JSON
187
+ const plaintext = textEncoder.encode(JSON.stringify(vault));
188
+
189
+ // Encrypt with AES-256-GCM
190
+ const ciphertext = await globalThis.crypto.subtle.encrypt(
191
+ { name: 'AES-GCM', iv },
192
+ key,
193
+ plaintext
194
+ );
195
+
196
+ return {
197
+ version: VAULT_ENCRYPTED_VERSION_V2,
198
+ kdf: VAULT_KDF_V2,
199
+ memoryCost: KDF_CONFIG_ARGON2ID.argon2MemoryCost!,
200
+ timeCost: KDF_CONFIG_ARGON2ID.argon2TimeCost!,
201
+ parallelism: KDF_CONFIG_ARGON2ID.argon2Parallelism!,
202
+ salt: toB64(salt),
203
+ iv: toB64(iv),
204
+ ciphertext: toB64(new Uint8Array(ciphertext)),
205
+ algorithm: VAULT_ALGORITHM,
206
+ };
207
+ }
@@ -0,0 +1,71 @@
1
+ /**
2
+ * Omnituum PQC Shared - Vault Exports
3
+ */
4
+
5
+ // Types
6
+ export type {
7
+ HybridIdentityRecord,
8
+ VaultSettings,
9
+ OmnituumVault,
10
+ EncryptedVaultFile,
11
+ EncryptedVaultFileV1,
12
+ EncryptedVaultFileV2,
13
+ HealthStatus,
14
+ IdentityHealth,
15
+ VaultSession,
16
+ } from './types';
17
+
18
+ export {
19
+ DEFAULT_VAULT_SETTINGS,
20
+ PBKDF2_ITERATIONS,
21
+ } from './types';
22
+
23
+ // Encryption
24
+ export {
25
+ deriveKey,
26
+ encryptVault,
27
+ encryptVaultV2,
28
+ encryptVaultToBlob,
29
+ encryptVaultToDataURL,
30
+ } from './encrypt';
31
+
32
+ // Decryption
33
+ export {
34
+ decryptVault,
35
+ decryptVaultFromJson,
36
+ decryptVaultFromFile,
37
+ isValidEncryptedVaultFile,
38
+ } from './decrypt';
39
+
40
+ // Manager
41
+ export {
42
+ createEmptyVault,
43
+ createIdentity,
44
+ addIdentity,
45
+ removeIdentity,
46
+ rotateIdentityKeys,
47
+ updateIdentityMetadata,
48
+ updateSettings,
49
+ setActiveIdentity,
50
+ exportVault,
51
+ importVault,
52
+ downloadVault,
53
+ getSession,
54
+ unlockSession,
55
+ lockSession,
56
+ setSessionActiveIdentity,
57
+ } from './manager';
58
+
59
+ // Migration
60
+ export type {
61
+ MigrationOptions,
62
+ MigrationResult,
63
+ } from './migrate';
64
+
65
+ export {
66
+ needsMigration,
67
+ isV2Vault,
68
+ getVaultKdfInfo,
69
+ migrateEncryptedVault,
70
+ validateMigration,
71
+ } from './migrate';