@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.
- package/LICENSE +22 -0
- package/README.md +543 -0
- package/dist/crypto/index.cjs +807 -0
- package/dist/crypto/index.d.cts +641 -0
- package/dist/crypto/index.d.ts +641 -0
- package/dist/crypto/index.js +716 -0
- package/dist/decrypt-eSHlbh1j.d.cts +321 -0
- package/dist/decrypt-eSHlbh1j.d.ts +321 -0
- package/dist/fs/index.cjs +1168 -0
- package/dist/fs/index.d.cts +400 -0
- package/dist/fs/index.d.ts +400 -0
- package/dist/fs/index.js +1091 -0
- package/dist/index.cjs +2160 -0
- package/dist/index.d.cts +282 -0
- package/dist/index.d.ts +282 -0
- package/dist/index.js +2031 -0
- package/dist/integrity-CCYjrap3.d.ts +31 -0
- package/dist/integrity-Dx9jukMH.d.cts +31 -0
- package/dist/types-61c7Q9ri.d.ts +134 -0
- package/dist/types-Ch0y-n7K.d.cts +134 -0
- package/dist/utils/index.cjs +129 -0
- package/dist/utils/index.d.cts +49 -0
- package/dist/utils/index.d.ts +49 -0
- package/dist/utils/index.js +114 -0
- package/dist/vault/index.cjs +713 -0
- package/dist/vault/index.d.cts +237 -0
- package/dist/vault/index.d.ts +237 -0
- package/dist/vault/index.js +677 -0
- package/dist/version-BygzPVGs.d.cts +55 -0
- package/dist/version-BygzPVGs.d.ts +55 -0
- package/package.json +86 -0
- package/src/crypto/dilithium.ts +233 -0
- package/src/crypto/hybrid.ts +358 -0
- package/src/crypto/index.ts +181 -0
- package/src/crypto/kyber.ts +199 -0
- package/src/crypto/nacl.ts +204 -0
- package/src/crypto/primitives/blake3.ts +141 -0
- package/src/crypto/primitives/chacha.ts +211 -0
- package/src/crypto/primitives/hkdf.ts +192 -0
- package/src/crypto/primitives/index.ts +54 -0
- package/src/crypto/primitives.ts +144 -0
- package/src/crypto/x25519.ts +134 -0
- package/src/fs/aes.ts +343 -0
- package/src/fs/argon2.ts +184 -0
- package/src/fs/browser.ts +408 -0
- package/src/fs/decrypt.ts +320 -0
- package/src/fs/encrypt.ts +324 -0
- package/src/fs/format.ts +425 -0
- package/src/fs/index.ts +144 -0
- package/src/fs/types.ts +304 -0
- package/src/index.ts +414 -0
- package/src/kdf/index.ts +311 -0
- package/src/runtime/crypto.ts +16 -0
- package/src/security/index.ts +345 -0
- package/src/tunnel/index.ts +39 -0
- package/src/tunnel/session.ts +229 -0
- package/src/tunnel/types.ts +115 -0
- package/src/utils/entropy.ts +128 -0
- package/src/utils/index.ts +25 -0
- package/src/utils/integrity.ts +95 -0
- package/src/vault/decrypt.ts +167 -0
- package/src/vault/encrypt.ts +207 -0
- package/src/vault/index.ts +71 -0
- package/src/vault/manager.ts +327 -0
- package/src/vault/migrate.ts +190 -0
- package/src/vault/types.ts +177 -0
- package/src/version.ts +304 -0
package/src/fs/format.ts
ADDED
|
@@ -0,0 +1,425 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Omnituum FS - OQE Binary Format
|
|
3
|
+
*
|
|
4
|
+
* Reader/writer for the .oqe (Omnituum Quantum Encrypted) file format.
|
|
5
|
+
* Implements a documented, stable binary format for encrypted files.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { textEncoder, textDecoder } from '../crypto/primitives';
|
|
9
|
+
import {
|
|
10
|
+
OQE_MAGIC,
|
|
11
|
+
OQE_FORMAT_VERSION,
|
|
12
|
+
OQE_HEADER_SIZE,
|
|
13
|
+
ALGORITHM_SUITES,
|
|
14
|
+
AlgorithmSuiteId,
|
|
15
|
+
OQEHeader,
|
|
16
|
+
OQEMetadata,
|
|
17
|
+
HybridKeyMaterial,
|
|
18
|
+
PasswordKeyMaterial,
|
|
19
|
+
OQEError,
|
|
20
|
+
} from './types';
|
|
21
|
+
|
|
22
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
23
|
+
// BINARY UTILITIES
|
|
24
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
25
|
+
|
|
26
|
+
function writeUint32BE(value: number): Uint8Array {
|
|
27
|
+
const buffer = new ArrayBuffer(4);
|
|
28
|
+
new DataView(buffer).setUint32(0, value, false);
|
|
29
|
+
return new Uint8Array(buffer);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function readUint32BE(data: Uint8Array, offset: number): number {
|
|
33
|
+
return new DataView(data.buffer, data.byteOffset + offset).getUint32(0, false);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function writeUint16BE(value: number): Uint8Array {
|
|
37
|
+
const buffer = new ArrayBuffer(2);
|
|
38
|
+
new DataView(buffer).setUint16(0, value, false);
|
|
39
|
+
return new Uint8Array(buffer);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function readUint16BE(data: Uint8Array, offset: number): number {
|
|
43
|
+
return new DataView(data.buffer, data.byteOffset + offset).getUint16(0, false);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
47
|
+
// OQE HEADER OPERATIONS
|
|
48
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Write an OQE file header.
|
|
52
|
+
*
|
|
53
|
+
* @param header - Header data
|
|
54
|
+
* @returns 30-byte header buffer
|
|
55
|
+
*/
|
|
56
|
+
export function writeOQEHeader(header: OQEHeader): Uint8Array {
|
|
57
|
+
const buffer = new Uint8Array(OQE_HEADER_SIZE);
|
|
58
|
+
let offset = 0;
|
|
59
|
+
|
|
60
|
+
// Magic bytes (4 bytes)
|
|
61
|
+
buffer.set(OQE_MAGIC, offset);
|
|
62
|
+
offset += 4;
|
|
63
|
+
|
|
64
|
+
// Version (1 byte)
|
|
65
|
+
buffer[offset++] = header.version;
|
|
66
|
+
|
|
67
|
+
// Algorithm suite (1 byte)
|
|
68
|
+
buffer[offset++] = header.algorithmSuite;
|
|
69
|
+
|
|
70
|
+
// Flags (4 bytes, reserved)
|
|
71
|
+
buffer.set(writeUint32BE(header.flags), offset);
|
|
72
|
+
offset += 4;
|
|
73
|
+
|
|
74
|
+
// Metadata length (4 bytes)
|
|
75
|
+
buffer.set(writeUint32BE(header.metadataLength), offset);
|
|
76
|
+
offset += 4;
|
|
77
|
+
|
|
78
|
+
// Key material length (4 bytes)
|
|
79
|
+
buffer.set(writeUint32BE(header.keyMaterialLength), offset);
|
|
80
|
+
offset += 4;
|
|
81
|
+
|
|
82
|
+
// IV (12 bytes)
|
|
83
|
+
buffer.set(header.iv, offset);
|
|
84
|
+
// offset += 12;
|
|
85
|
+
|
|
86
|
+
return buffer;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Parse an OQE file header.
|
|
91
|
+
*
|
|
92
|
+
* @param data - File data (at least 30 bytes)
|
|
93
|
+
* @returns Parsed header
|
|
94
|
+
* @throws OQEError if header is invalid
|
|
95
|
+
*/
|
|
96
|
+
export function parseOQEHeader(data: Uint8Array): OQEHeader {
|
|
97
|
+
if (data.length < OQE_HEADER_SIZE) {
|
|
98
|
+
throw new OQEError('INVALID_HEADER', `File too small: need ${OQE_HEADER_SIZE} bytes, got ${data.length}`);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
let offset = 0;
|
|
102
|
+
|
|
103
|
+
// Validate magic bytes
|
|
104
|
+
const magic = data.slice(0, 4);
|
|
105
|
+
if (!magic.every((b, i) => b === OQE_MAGIC[i])) {
|
|
106
|
+
throw new OQEError('INVALID_MAGIC', 'Not a valid OQE file (invalid magic bytes)');
|
|
107
|
+
}
|
|
108
|
+
offset += 4;
|
|
109
|
+
|
|
110
|
+
// Version
|
|
111
|
+
const version = data[offset++];
|
|
112
|
+
if (version !== OQE_FORMAT_VERSION) {
|
|
113
|
+
throw new OQEError('UNSUPPORTED_VERSION', `Unsupported OQE version: ${version}`);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// Algorithm suite
|
|
117
|
+
const algorithmSuiteRaw = data[offset++];
|
|
118
|
+
if (
|
|
119
|
+
algorithmSuiteRaw !== ALGORITHM_SUITES.HYBRID_X25519_KYBER768_AES256GCM &&
|
|
120
|
+
algorithmSuiteRaw !== ALGORITHM_SUITES.PASSWORD_ARGON2ID_AES256GCM
|
|
121
|
+
) {
|
|
122
|
+
throw new OQEError('UNSUPPORTED_ALGORITHM', `Unsupported algorithm suite: 0x${algorithmSuiteRaw.toString(16)}`);
|
|
123
|
+
}
|
|
124
|
+
const algorithmSuite = algorithmSuiteRaw as AlgorithmSuiteId;
|
|
125
|
+
|
|
126
|
+
// Flags
|
|
127
|
+
const flags = readUint32BE(data, offset);
|
|
128
|
+
offset += 4;
|
|
129
|
+
|
|
130
|
+
// Metadata length
|
|
131
|
+
const metadataLength = readUint32BE(data, offset);
|
|
132
|
+
offset += 4;
|
|
133
|
+
|
|
134
|
+
// Key material length
|
|
135
|
+
const keyMaterialLength = readUint32BE(data, offset);
|
|
136
|
+
offset += 4;
|
|
137
|
+
|
|
138
|
+
// IV
|
|
139
|
+
const iv = data.slice(offset, offset + 12);
|
|
140
|
+
|
|
141
|
+
return {
|
|
142
|
+
version,
|
|
143
|
+
algorithmSuite,
|
|
144
|
+
flags,
|
|
145
|
+
metadataLength,
|
|
146
|
+
keyMaterialLength,
|
|
147
|
+
iv,
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
152
|
+
// KEY MATERIAL SERIALIZATION
|
|
153
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Serialize hybrid mode key material.
|
|
157
|
+
*
|
|
158
|
+
* Format:
|
|
159
|
+
* - X25519 ephemeral PK (32 bytes)
|
|
160
|
+
* - X25519 nonce (24 bytes)
|
|
161
|
+
* - X25519 wrapped key length (2 bytes)
|
|
162
|
+
* - X25519 wrapped key (variable)
|
|
163
|
+
* - Kyber ciphertext length (2 bytes)
|
|
164
|
+
* - Kyber ciphertext (variable, ~1088 bytes)
|
|
165
|
+
* - Kyber nonce (24 bytes)
|
|
166
|
+
* - Kyber wrapped key length (2 bytes)
|
|
167
|
+
* - Kyber wrapped key (variable)
|
|
168
|
+
*/
|
|
169
|
+
export function serializeHybridKeyMaterial(km: HybridKeyMaterial): Uint8Array {
|
|
170
|
+
const parts: Uint8Array[] = [];
|
|
171
|
+
|
|
172
|
+
// X25519 ephemeral public key (32 bytes)
|
|
173
|
+
parts.push(km.x25519EphemeralPk);
|
|
174
|
+
|
|
175
|
+
// X25519 nonce (24 bytes)
|
|
176
|
+
parts.push(km.x25519Nonce);
|
|
177
|
+
|
|
178
|
+
// X25519 wrapped key (length + data)
|
|
179
|
+
parts.push(writeUint16BE(km.x25519WrappedKey.length));
|
|
180
|
+
parts.push(km.x25519WrappedKey);
|
|
181
|
+
|
|
182
|
+
// Kyber ciphertext (length + data)
|
|
183
|
+
parts.push(writeUint16BE(km.kyberCiphertext.length));
|
|
184
|
+
parts.push(km.kyberCiphertext);
|
|
185
|
+
|
|
186
|
+
// Kyber nonce (24 bytes)
|
|
187
|
+
parts.push(km.kyberNonce);
|
|
188
|
+
|
|
189
|
+
// Kyber wrapped key (length + data)
|
|
190
|
+
parts.push(writeUint16BE(km.kyberWrappedKey.length));
|
|
191
|
+
parts.push(km.kyberWrappedKey);
|
|
192
|
+
|
|
193
|
+
// Combine all parts
|
|
194
|
+
const totalLength = parts.reduce((sum, p) => sum + p.length, 0);
|
|
195
|
+
const result = new Uint8Array(totalLength);
|
|
196
|
+
let offset = 0;
|
|
197
|
+
for (const part of parts) {
|
|
198
|
+
result.set(part, offset);
|
|
199
|
+
offset += part.length;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
return result;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Parse hybrid mode key material.
|
|
207
|
+
*/
|
|
208
|
+
export function parseHybridKeyMaterial(data: Uint8Array): HybridKeyMaterial {
|
|
209
|
+
let offset = 0;
|
|
210
|
+
|
|
211
|
+
// X25519 ephemeral public key (32 bytes)
|
|
212
|
+
const x25519EphemeralPk = data.slice(offset, offset + 32);
|
|
213
|
+
offset += 32;
|
|
214
|
+
|
|
215
|
+
// X25519 nonce (24 bytes)
|
|
216
|
+
const x25519Nonce = data.slice(offset, offset + 24);
|
|
217
|
+
offset += 24;
|
|
218
|
+
|
|
219
|
+
// X25519 wrapped key
|
|
220
|
+
const x25519WrappedLen = readUint16BE(data, offset);
|
|
221
|
+
offset += 2;
|
|
222
|
+
const x25519WrappedKey = data.slice(offset, offset + x25519WrappedLen);
|
|
223
|
+
offset += x25519WrappedLen;
|
|
224
|
+
|
|
225
|
+
// Kyber ciphertext
|
|
226
|
+
const kyberCtLen = readUint16BE(data, offset);
|
|
227
|
+
offset += 2;
|
|
228
|
+
const kyberCiphertext = data.slice(offset, offset + kyberCtLen);
|
|
229
|
+
offset += kyberCtLen;
|
|
230
|
+
|
|
231
|
+
// Kyber nonce (24 bytes)
|
|
232
|
+
const kyberNonce = data.slice(offset, offset + 24);
|
|
233
|
+
offset += 24;
|
|
234
|
+
|
|
235
|
+
// Kyber wrapped key
|
|
236
|
+
const kyberWrappedLen = readUint16BE(data, offset);
|
|
237
|
+
offset += 2;
|
|
238
|
+
const kyberWrappedKey = data.slice(offset, offset + kyberWrappedLen);
|
|
239
|
+
|
|
240
|
+
return {
|
|
241
|
+
x25519EphemeralPk,
|
|
242
|
+
x25519Nonce,
|
|
243
|
+
x25519WrappedKey,
|
|
244
|
+
kyberCiphertext,
|
|
245
|
+
kyberNonce,
|
|
246
|
+
kyberWrappedKey,
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* Serialize password mode key material.
|
|
252
|
+
*
|
|
253
|
+
* Format:
|
|
254
|
+
* - Salt (32 bytes)
|
|
255
|
+
* - Memory cost (4 bytes, KiB)
|
|
256
|
+
* - Time cost (4 bytes)
|
|
257
|
+
* - Parallelism (4 bytes)
|
|
258
|
+
*/
|
|
259
|
+
export function serializePasswordKeyMaterial(km: PasswordKeyMaterial): Uint8Array {
|
|
260
|
+
const result = new Uint8Array(32 + 4 + 4 + 4);
|
|
261
|
+
|
|
262
|
+
result.set(km.salt, 0);
|
|
263
|
+
result.set(writeUint32BE(km.memoryCost), 32);
|
|
264
|
+
result.set(writeUint32BE(km.timeCost), 36);
|
|
265
|
+
result.set(writeUint32BE(km.parallelism), 40);
|
|
266
|
+
|
|
267
|
+
return result;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* Parse password mode key material.
|
|
272
|
+
*/
|
|
273
|
+
export function parsePasswordKeyMaterial(data: Uint8Array): PasswordKeyMaterial {
|
|
274
|
+
return {
|
|
275
|
+
salt: data.slice(0, 32),
|
|
276
|
+
memoryCost: readUint32BE(data, 32),
|
|
277
|
+
timeCost: readUint32BE(data, 36),
|
|
278
|
+
parallelism: readUint32BE(data, 40),
|
|
279
|
+
};
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
283
|
+
// METADATA SERIALIZATION
|
|
284
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* Serialize metadata to JSON bytes.
|
|
288
|
+
*/
|
|
289
|
+
export function serializeMetadata(metadata: OQEMetadata): Uint8Array {
|
|
290
|
+
const json = JSON.stringify(metadata);
|
|
291
|
+
return textEncoder.encode(json);
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
/**
|
|
295
|
+
* Parse metadata from JSON bytes.
|
|
296
|
+
*/
|
|
297
|
+
export function parseMetadata(data: Uint8Array): OQEMetadata {
|
|
298
|
+
const json = textDecoder.decode(data);
|
|
299
|
+
return JSON.parse(json);
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
303
|
+
// COMPLETE FILE OPERATIONS
|
|
304
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
305
|
+
|
|
306
|
+
export interface OQEFileComponents {
|
|
307
|
+
header: OQEHeader;
|
|
308
|
+
keyMaterial: Uint8Array;
|
|
309
|
+
encryptedMetadata: Uint8Array;
|
|
310
|
+
encryptedContent: Uint8Array;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
/**
|
|
314
|
+
* Assemble a complete OQE file from components.
|
|
315
|
+
*/
|
|
316
|
+
export function assembleOQEFile(components: OQEFileComponents): Uint8Array {
|
|
317
|
+
const { header, keyMaterial, encryptedMetadata, encryptedContent } = components;
|
|
318
|
+
|
|
319
|
+
const headerBytes = writeOQEHeader(header);
|
|
320
|
+
const totalLength =
|
|
321
|
+
headerBytes.length + keyMaterial.length + encryptedMetadata.length + encryptedContent.length;
|
|
322
|
+
|
|
323
|
+
const result = new Uint8Array(totalLength);
|
|
324
|
+
let offset = 0;
|
|
325
|
+
|
|
326
|
+
result.set(headerBytes, offset);
|
|
327
|
+
offset += headerBytes.length;
|
|
328
|
+
|
|
329
|
+
result.set(keyMaterial, offset);
|
|
330
|
+
offset += keyMaterial.length;
|
|
331
|
+
|
|
332
|
+
result.set(encryptedMetadata, offset);
|
|
333
|
+
offset += encryptedMetadata.length;
|
|
334
|
+
|
|
335
|
+
result.set(encryptedContent, offset);
|
|
336
|
+
|
|
337
|
+
return result;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
/**
|
|
341
|
+
* Parse a complete OQE file into components.
|
|
342
|
+
*/
|
|
343
|
+
export function parseOQEFile(data: Uint8Array): OQEFileComponents {
|
|
344
|
+
const header = parseOQEHeader(data);
|
|
345
|
+
|
|
346
|
+
let offset = OQE_HEADER_SIZE;
|
|
347
|
+
|
|
348
|
+
// Key material
|
|
349
|
+
const keyMaterial = data.slice(offset, offset + header.keyMaterialLength);
|
|
350
|
+
offset += header.keyMaterialLength;
|
|
351
|
+
|
|
352
|
+
// Encrypted metadata
|
|
353
|
+
const encryptedMetadata = data.slice(offset, offset + header.metadataLength);
|
|
354
|
+
offset += header.metadataLength;
|
|
355
|
+
|
|
356
|
+
// Encrypted content (rest of file)
|
|
357
|
+
const encryptedContent = data.slice(offset);
|
|
358
|
+
|
|
359
|
+
return {
|
|
360
|
+
header,
|
|
361
|
+
keyMaterial,
|
|
362
|
+
encryptedMetadata,
|
|
363
|
+
encryptedContent,
|
|
364
|
+
};
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
368
|
+
// FILE EXTENSION HANDLING
|
|
369
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
370
|
+
|
|
371
|
+
/** OQE file extension */
|
|
372
|
+
export const OQE_EXTENSION = '.oqe';
|
|
373
|
+
|
|
374
|
+
/**
|
|
375
|
+
* Add .oqe extension to a filename.
|
|
376
|
+
*/
|
|
377
|
+
export function addOQEExtension(filename: string): string {
|
|
378
|
+
if (filename.toLowerCase().endsWith(OQE_EXTENSION)) {
|
|
379
|
+
return filename;
|
|
380
|
+
}
|
|
381
|
+
return `${filename}${OQE_EXTENSION}`;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
/**
|
|
385
|
+
* Remove .oqe extension from a filename.
|
|
386
|
+
*/
|
|
387
|
+
export function removeOQEExtension(filename: string): string {
|
|
388
|
+
if (filename.toLowerCase().endsWith(OQE_EXTENSION)) {
|
|
389
|
+
return filename.slice(0, -OQE_EXTENSION.length);
|
|
390
|
+
}
|
|
391
|
+
return filename;
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
/**
|
|
395
|
+
* Check if a file is an OQE file (by extension or magic bytes).
|
|
396
|
+
*/
|
|
397
|
+
export function isOQEFile(filenameOrData: string | Uint8Array): boolean {
|
|
398
|
+
if (typeof filenameOrData === 'string') {
|
|
399
|
+
return filenameOrData.toLowerCase().endsWith(OQE_EXTENSION);
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
// Check magic bytes
|
|
403
|
+
if (filenameOrData.length < 4) return false;
|
|
404
|
+
return filenameOrData.slice(0, 4).every((b, i) => b === OQE_MAGIC[i]);
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
408
|
+
// MIME TYPE
|
|
409
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
410
|
+
|
|
411
|
+
/** OQE MIME type */
|
|
412
|
+
export const OQE_MIME_TYPE = 'application/x-omnituum-encrypted';
|
|
413
|
+
|
|
414
|
+
/**
|
|
415
|
+
* Get a display-friendly algorithm name from suite ID.
|
|
416
|
+
*/
|
|
417
|
+
export function getAlgorithmName(suiteId: AlgorithmSuiteId): string {
|
|
418
|
+
if (suiteId === ALGORITHM_SUITES.HYBRID_X25519_KYBER768_AES256GCM) {
|
|
419
|
+
return 'Hybrid (X25519 + Kyber768 + AES-256-GCM)';
|
|
420
|
+
}
|
|
421
|
+
if (suiteId === ALGORITHM_SUITES.PASSWORD_ARGON2ID_AES256GCM) {
|
|
422
|
+
return 'Password (Argon2id + AES-256-GCM)';
|
|
423
|
+
}
|
|
424
|
+
return `Unknown (0x${(suiteId as number).toString(16)})`;
|
|
425
|
+
}
|
package/src/fs/index.ts
ADDED
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Omnituum FS - File Encryption Module
|
|
3
|
+
*
|
|
4
|
+
* Post-quantum secure file encryption for any file type.
|
|
5
|
+
* Supports two modes:
|
|
6
|
+
* - Hybrid: X25519 + Kyber768 + AES-256-GCM (identity-based)
|
|
7
|
+
* - Password: Argon2id + AES-256-GCM (standalone)
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* // Encrypt with hybrid mode (using identity)
|
|
11
|
+
* import { encryptFile, decryptFile } from '@omnituum/pqc-shared/fs';
|
|
12
|
+
*
|
|
13
|
+
* const encrypted = await encryptFile(
|
|
14
|
+
* { data: fileBytes, filename: 'secret.pdf' },
|
|
15
|
+
* { mode: 'hybrid', recipientPublicKeys: identity.getPublicKeys() }
|
|
16
|
+
* );
|
|
17
|
+
*
|
|
18
|
+
* // Download encrypted file
|
|
19
|
+
* downloadEncryptedFile(encrypted);
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* // Encrypt with password (standalone)
|
|
23
|
+
* const encrypted = await encryptFileWithPassword(
|
|
24
|
+
* { data: fileBytes, filename: 'secret.pdf' },
|
|
25
|
+
* 'my-secure-password'
|
|
26
|
+
* );
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
// Types
|
|
30
|
+
export * from './types';
|
|
31
|
+
|
|
32
|
+
// Argon2id key derivation
|
|
33
|
+
export {
|
|
34
|
+
deriveKeyFromPassword,
|
|
35
|
+
generateArgon2Salt,
|
|
36
|
+
verifyPassword,
|
|
37
|
+
estimateArgon2Params,
|
|
38
|
+
benchmarkArgon2,
|
|
39
|
+
isArgon2Available,
|
|
40
|
+
DEFAULT_ARGON2ID_PARAMS,
|
|
41
|
+
MIN_ARGON2ID_PARAMS,
|
|
42
|
+
} from './argon2';
|
|
43
|
+
|
|
44
|
+
// AES-256-GCM encryption
|
|
45
|
+
export {
|
|
46
|
+
AES_KEY_SIZE,
|
|
47
|
+
AES_GCM_IV_SIZE,
|
|
48
|
+
AES_GCM_TAG_SIZE,
|
|
49
|
+
importAesKey,
|
|
50
|
+
generateAesKey,
|
|
51
|
+
exportAesKey,
|
|
52
|
+
aesEncrypt,
|
|
53
|
+
aesEncryptCombined,
|
|
54
|
+
aesDecrypt,
|
|
55
|
+
aesDecryptCombined,
|
|
56
|
+
aesEncryptStreaming,
|
|
57
|
+
aesDecryptStreaming,
|
|
58
|
+
STREAM_CHUNK_SIZE,
|
|
59
|
+
} from './aes';
|
|
60
|
+
|
|
61
|
+
// OQE format operations
|
|
62
|
+
export {
|
|
63
|
+
writeOQEHeader,
|
|
64
|
+
parseOQEHeader,
|
|
65
|
+
serializeHybridKeyMaterial,
|
|
66
|
+
parseHybridKeyMaterial,
|
|
67
|
+
serializePasswordKeyMaterial,
|
|
68
|
+
parsePasswordKeyMaterial,
|
|
69
|
+
serializeMetadata,
|
|
70
|
+
parseMetadata,
|
|
71
|
+
assembleOQEFile,
|
|
72
|
+
parseOQEFile,
|
|
73
|
+
OQE_EXTENSION,
|
|
74
|
+
addOQEExtension,
|
|
75
|
+
removeOQEExtension,
|
|
76
|
+
isOQEFile,
|
|
77
|
+
OQE_MIME_TYPE,
|
|
78
|
+
getAlgorithmName,
|
|
79
|
+
} from './format';
|
|
80
|
+
|
|
81
|
+
// Main encryption API
|
|
82
|
+
export {
|
|
83
|
+
encryptFile,
|
|
84
|
+
encryptFileForSelf,
|
|
85
|
+
encryptFileWithPassword,
|
|
86
|
+
} from './encrypt';
|
|
87
|
+
|
|
88
|
+
// Main decryption API
|
|
89
|
+
export {
|
|
90
|
+
decryptFile,
|
|
91
|
+
decryptFileForSelf,
|
|
92
|
+
decryptFileWithPassword,
|
|
93
|
+
inspectOQEFile,
|
|
94
|
+
} from './decrypt';
|
|
95
|
+
|
|
96
|
+
// Browser utilities
|
|
97
|
+
export {
|
|
98
|
+
downloadEncryptedFile,
|
|
99
|
+
downloadDecryptedFile,
|
|
100
|
+
downloadBlob,
|
|
101
|
+
downloadBytes,
|
|
102
|
+
readFile,
|
|
103
|
+
readFileAsText,
|
|
104
|
+
readFileAsDataURL,
|
|
105
|
+
createDropZone,
|
|
106
|
+
openFilePicker,
|
|
107
|
+
openOQEFilePicker,
|
|
108
|
+
openFileToEncrypt,
|
|
109
|
+
encryptResultToBlob,
|
|
110
|
+
decryptResultToBlob,
|
|
111
|
+
createObjectURL,
|
|
112
|
+
bytesToDataURL,
|
|
113
|
+
getFileInfo,
|
|
114
|
+
formatFileSize,
|
|
115
|
+
copyToClipboard,
|
|
116
|
+
isBrowser,
|
|
117
|
+
isWebCryptoAvailable,
|
|
118
|
+
isFileAPIAvailable,
|
|
119
|
+
isDragDropSupported,
|
|
120
|
+
} from './browser';
|
|
121
|
+
|
|
122
|
+
// Re-export key types for convenience
|
|
123
|
+
export type {
|
|
124
|
+
OQEMode,
|
|
125
|
+
AlgorithmSuiteId,
|
|
126
|
+
Argon2idParams,
|
|
127
|
+
OQEMetadata,
|
|
128
|
+
OQEHeader,
|
|
129
|
+
HybridKeyMaterial,
|
|
130
|
+
PasswordKeyMaterial,
|
|
131
|
+
HybridEncryptOptions,
|
|
132
|
+
PasswordEncryptOptions,
|
|
133
|
+
EncryptOptions,
|
|
134
|
+
HybridDecryptOptions,
|
|
135
|
+
PasswordDecryptOptions,
|
|
136
|
+
DecryptOptions,
|
|
137
|
+
OQEEncryptResult,
|
|
138
|
+
OQEDecryptResult,
|
|
139
|
+
OQEErrorCode,
|
|
140
|
+
ProgressCallback,
|
|
141
|
+
FileInput,
|
|
142
|
+
} from './types';
|
|
143
|
+
|
|
144
|
+
export { OQEError } from './types';
|