@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/LICENSE
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
SPDX-License-Identifier: MIT
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025–2026 Nathan Cowan
|
|
4
|
+
Copyright (c) 2025–2026 Omnituum
|
|
5
|
+
|
|
6
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
7
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
8
|
+
in the Software without restriction, including without limitation the rights
|
|
9
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
10
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
11
|
+
furnished to do so, subject to the following conditions:
|
|
12
|
+
|
|
13
|
+
The above copyright notice and this permission notice shall be included in all
|
|
14
|
+
copies or substantial portions of the Software.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
17
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
18
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
19
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
20
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
21
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
22
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,543 @@
|
|
|
1
|
+
# @omnituum/pqc-shared
|
|
2
|
+
|
|
3
|
+
Post-Quantum Cryptography library for hybrid encryption, identity management, and secure file handling.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Hybrid Encryption** — X25519 + ML-KEM-768 (Kyber) dual-layer security
|
|
8
|
+
- **Post-Quantum Signatures** — ML-DSA-65 (Dilithium) via `@noble/post-quantum`
|
|
9
|
+
- **Identity Vault** — Encrypted storage with Argon2id key derivation
|
|
10
|
+
- **File Encryption** — `.oqe` format with hybrid or password-based modes
|
|
11
|
+
- **Cross-Platform** — Works in Node.js and modern browsers; no native bindings
|
|
12
|
+
|
|
13
|
+
## Installation
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm install @omnituum/pqc-shared
|
|
17
|
+
# or
|
|
18
|
+
pnpm add @omnituum/pqc-shared
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Supported Environments
|
|
22
|
+
|
|
23
|
+
`@omnituum/pqc-shared` is designed to run in both Node.js and modern browsers.
|
|
24
|
+
|
|
25
|
+
- **Node.js:** 18, 20, 22
|
|
26
|
+
- **Browsers:** modern Chromium / Firefox / Safari with WebCrypto support
|
|
27
|
+
|
|
28
|
+
### Cryptographic runtime behavior
|
|
29
|
+
|
|
30
|
+
- In browsers, the library uses **WebCrypto** (`globalThis.crypto`) when available.
|
|
31
|
+
- In Node.js, the library uses **Node built-ins** (e.g. `crypto`) as a fallback when WebCrypto globals are unavailable.
|
|
32
|
+
|
|
33
|
+
If you bundle for the browser, ensure your bundler targets web environments and does not force Node polyfills unless explicitly intended.
|
|
34
|
+
|
|
35
|
+
## Non-Goals
|
|
36
|
+
|
|
37
|
+
This package provides **cryptographic primitives and utilities**. It does **not** provide:
|
|
38
|
+
|
|
39
|
+
- Custodial services, hosting, or key escrow
|
|
40
|
+
- User authentication, identity proofing, or account recovery
|
|
41
|
+
- Network transport, relays, or message delivery guarantees
|
|
42
|
+
- Compliance certification (audit/compliance is handled at the system + deployment layer)
|
|
43
|
+
|
|
44
|
+
## Security Status
|
|
45
|
+
|
|
46
|
+
This repository is **pre-audit**. It includes golden test vectors for regression detection.
|
|
47
|
+
If you plan to use this library in high-stakes environments, perform an independent review and validate the threat model for your deployment.
|
|
48
|
+
|
|
49
|
+
## API Stability
|
|
50
|
+
|
|
51
|
+
Exports are annotated with stability markers:
|
|
52
|
+
|
|
53
|
+
- **`@stable`** — Supported and semver-governed. Breaking changes only in major versions.
|
|
54
|
+
- **`@experimental`** — May change in minor/patch releases until stabilized.
|
|
55
|
+
|
|
56
|
+
The public API surface is the root exports (`@omnituum/pqc-shared`). Subpath exports (`/crypto`, `/vault`, `/fs`, `/utils`) may evolve faster and are intended for advanced use cases.
|
|
57
|
+
|
|
58
|
+
## Quick Start
|
|
59
|
+
|
|
60
|
+
### Hybrid Encryption
|
|
61
|
+
|
|
62
|
+
```typescript
|
|
63
|
+
import {
|
|
64
|
+
generateHybridIdentity,
|
|
65
|
+
hybridEncrypt,
|
|
66
|
+
hybridDecryptToString,
|
|
67
|
+
getPublicKeys,
|
|
68
|
+
} from '@omnituum/pqc-shared';
|
|
69
|
+
|
|
70
|
+
// Generate identity with X25519 + Kyber keypairs
|
|
71
|
+
const alice = await generateHybridIdentity('Alice');
|
|
72
|
+
const bob = await generateHybridIdentity('Bob');
|
|
73
|
+
|
|
74
|
+
// Encrypt message for Bob using his public keys
|
|
75
|
+
const bobPublicKeys = getPublicKeys(bob);
|
|
76
|
+
const envelope = await hybridEncrypt(
|
|
77
|
+
'Hello, Bob!',
|
|
78
|
+
bobPublicKeys,
|
|
79
|
+
{ senderName: alice.name, senderId: alice.id }
|
|
80
|
+
);
|
|
81
|
+
|
|
82
|
+
// Bob decrypts with his secret keys
|
|
83
|
+
const plaintext = await hybridDecryptToString(envelope, bob);
|
|
84
|
+
console.log(plaintext); // "Hello, Bob!"
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### Digital Signatures (Dilithium)
|
|
88
|
+
|
|
89
|
+
```typescript
|
|
90
|
+
import {
|
|
91
|
+
generateDilithiumKeypair,
|
|
92
|
+
dilithiumSign,
|
|
93
|
+
dilithiumVerify,
|
|
94
|
+
} from '@omnituum/pqc-shared';
|
|
95
|
+
|
|
96
|
+
const keypair = await generateDilithiumKeypair();
|
|
97
|
+
const message = new TextEncoder().encode('Sign this message');
|
|
98
|
+
|
|
99
|
+
const { signature } = await dilithiumSign(message, keypair.secretB64);
|
|
100
|
+
const valid = await dilithiumVerify(message, signature, keypair.publicB64);
|
|
101
|
+
console.log(valid); // true
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### Vault Management
|
|
105
|
+
|
|
106
|
+
```typescript
|
|
107
|
+
import {
|
|
108
|
+
createEmptyVault,
|
|
109
|
+
generateHybridIdentity,
|
|
110
|
+
addIdentity,
|
|
111
|
+
encryptVault,
|
|
112
|
+
decryptVault,
|
|
113
|
+
} from '@omnituum/pqc-shared';
|
|
114
|
+
|
|
115
|
+
// Create and populate vault
|
|
116
|
+
let vault = createEmptyVault();
|
|
117
|
+
const identity = await generateHybridIdentity('My Identity');
|
|
118
|
+
vault = addIdentity(vault, identity);
|
|
119
|
+
|
|
120
|
+
// Encrypt vault with password (uses Argon2id)
|
|
121
|
+
const encrypted = await encryptVault(vault, 'my-password');
|
|
122
|
+
|
|
123
|
+
// Decrypt vault
|
|
124
|
+
const decrypted = await decryptVault(encrypted, 'my-password');
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### File Encryption
|
|
128
|
+
|
|
129
|
+
> **Note:** File encryption APIs accept browser `File`/`Blob` objects. For Node.js usage, use `Uint8Array` with the underlying hybrid encryption functions directly.
|
|
130
|
+
|
|
131
|
+
```typescript
|
|
132
|
+
import { encryptFile, decryptFile } from '@omnituum/pqc-shared';
|
|
133
|
+
|
|
134
|
+
// Encrypt file for recipient (browser)
|
|
135
|
+
const result = await encryptFile(fileData, recipientPublicKeys, senderIdentity, {
|
|
136
|
+
filename: 'document.pdf',
|
|
137
|
+
mimeType: 'application/pdf',
|
|
138
|
+
});
|
|
139
|
+
// result.encrypted contains .oqe file bytes
|
|
140
|
+
|
|
141
|
+
// Decrypt file
|
|
142
|
+
const decrypted = await decryptFile(oqeBytes, recipientIdentity);
|
|
143
|
+
console.log(decrypted.metadata.filename); // "document.pdf"
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
---
|
|
147
|
+
|
|
148
|
+
## API Reference
|
|
149
|
+
|
|
150
|
+
### Hybrid Encryption
|
|
151
|
+
|
|
152
|
+
| Function | Description |
|
|
153
|
+
|----------|-------------|
|
|
154
|
+
| `generateHybridIdentity(name)` | Create identity with X25519 + Kyber keypairs |
|
|
155
|
+
| `hybridEncrypt(plaintext, recipientPubKeys, meta?)` | Encrypt using hybrid encryption |
|
|
156
|
+
| `hybridDecrypt(envelope, recipientIdentity)` | Decrypt hybrid envelope |
|
|
157
|
+
| `hybridDecryptToString(envelope, recipientIdentity)` | Decrypt to UTF-8 string |
|
|
158
|
+
| `getPublicKeys(identity)` | Extract public keys from identity |
|
|
159
|
+
| `getSecretKeys(identity)` | Extract secret keys from identity |
|
|
160
|
+
|
|
161
|
+
### ML-KEM-768 (Kyber)
|
|
162
|
+
|
|
163
|
+
| Function | Description |
|
|
164
|
+
|----------|-------------|
|
|
165
|
+
| `isKyberAvailable()` | Check if Kyber library is available |
|
|
166
|
+
| `generateKyberKeypair()` | Generate Kyber keypair |
|
|
167
|
+
| `kyberEncapsulate(publicKeyB64)` | Create shared secret + ciphertext |
|
|
168
|
+
| `kyberDecapsulate(ciphertextB64, secretKeyB64)` | Recover shared secret |
|
|
169
|
+
| `kyberWrapKey(symKey, publicKeyB64)` | Wrap symmetric key |
|
|
170
|
+
| `kyberUnwrapKey(wrapped, secretKeyB64)` | Unwrap symmetric key |
|
|
171
|
+
|
|
172
|
+
### X25519
|
|
173
|
+
|
|
174
|
+
| Function | Description |
|
|
175
|
+
|----------|-------------|
|
|
176
|
+
| `generateX25519Keypair()` | Generate ECDH keypair |
|
|
177
|
+
| `generateX25519KeypairFromSeed(seed)` | Deterministic keypair from seed |
|
|
178
|
+
| `boxWrapWithX25519(symKey, recipientPubKeyHex)` | Wrap key with ECDH |
|
|
179
|
+
| `boxUnwrapWithX25519(wrap, secretKey)` | Unwrap key |
|
|
180
|
+
| `x25519SharedSecret(ourSecret, theirPublic)` | Raw scalar multiplication |
|
|
181
|
+
| `deriveKeyFromShared(shared, salt, info)` | HKDF derivation |
|
|
182
|
+
|
|
183
|
+
### Dilithium ML-DSA-65
|
|
184
|
+
|
|
185
|
+
| Function | Description |
|
|
186
|
+
|----------|-------------|
|
|
187
|
+
| `isDilithiumAvailable()` | Check if Dilithium library is available |
|
|
188
|
+
| `generateDilithiumKeypair()` | Generate signature keypair |
|
|
189
|
+
| `generateDilithiumKeypairFromSeed(seed)` | Deterministic generation |
|
|
190
|
+
| `dilithiumSign(message, secretKeyB64)` | Sign message (base64 output) |
|
|
191
|
+
| `dilithiumSignRaw(message, secretKeyB64)` | Sign message (Uint8Array output) |
|
|
192
|
+
| `dilithiumVerify(message, signatureB64, publicKeyB64)` | Verify signature |
|
|
193
|
+
| `dilithiumVerifyRaw(message, signature, publicKey)` | Verify with raw bytes |
|
|
194
|
+
|
|
195
|
+
**Key Sizes:**
|
|
196
|
+
- Public Key: 1952 bytes
|
|
197
|
+
- Secret Key: 4032 bytes
|
|
198
|
+
- Signature: 3309 bytes
|
|
199
|
+
|
|
200
|
+
### Vault Management
|
|
201
|
+
|
|
202
|
+
| Function | Description |
|
|
203
|
+
|----------|-------------|
|
|
204
|
+
| `createEmptyVault()` | Initialize empty vault |
|
|
205
|
+
| `createIdentity(name)` | Create new hybrid identity |
|
|
206
|
+
| `addIdentity(vault, identity)` | Add identity to vault |
|
|
207
|
+
| `removeIdentity(vault, identityId)` | Remove identity from vault |
|
|
208
|
+
| `rotateIdentityKeys(identity)` | Rotate all keys for identity |
|
|
209
|
+
| `setActiveIdentity(vault, identityId)` | Set default identity |
|
|
210
|
+
| `encryptVault(vault, password)` | Encrypt vault (Argon2id) |
|
|
211
|
+
| `decryptVault(encryptedVault, password)` | Decrypt vault |
|
|
212
|
+
| `exportVault(vault, password)` | Serialize to JSON string |
|
|
213
|
+
| `importVault(json, password)` | Deserialize from JSON |
|
|
214
|
+
|
|
215
|
+
### Vault Migration
|
|
216
|
+
|
|
217
|
+
| Function | Description |
|
|
218
|
+
|----------|-------------|
|
|
219
|
+
| `needsMigration(encryptedVault)` | Check if vault uses PBKDF2 |
|
|
220
|
+
| `isV2Vault(encryptedVault)` | Check if vault uses Argon2id |
|
|
221
|
+
| `migrateEncryptedVault(vault, oldPw, newPw)` | Migrate PBKDF2 → Argon2id |
|
|
222
|
+
| `getVaultKdfInfo(encryptedVault)` | Get KDF metadata |
|
|
223
|
+
|
|
224
|
+
### Key Derivation
|
|
225
|
+
|
|
226
|
+
| Function | Description |
|
|
227
|
+
|----------|-------------|
|
|
228
|
+
| `getRecommendedConfig()` | Get optimal KDF config for platform |
|
|
229
|
+
| `benchmarkKDF(config, iterations)` | Measure KDF performance |
|
|
230
|
+
| `kdfDeriveKey(password, salt, config)` | Derive key from password |
|
|
231
|
+
| `generateSalt(length?)` | Generate random salt |
|
|
232
|
+
|
|
233
|
+
**KDF Configurations:**
|
|
234
|
+
- `KDF_CONFIG_ARGON2ID` — Memory: 64MB, Time: 3, Parallelism: 4
|
|
235
|
+
- `KDF_CONFIG_PBKDF2` — 600,000 iterations (OWASP 2023)
|
|
236
|
+
|
|
237
|
+
### File Encryption
|
|
238
|
+
|
|
239
|
+
| Function | Description |
|
|
240
|
+
|----------|-------------|
|
|
241
|
+
| `encryptFile(data, recipientPubKeys, sender, opts)` | Hybrid file encryption |
|
|
242
|
+
| `decryptFile(oqeBytes, recipientIdentity)` | Decrypt .oqe file |
|
|
243
|
+
| `encryptFileWithPassword(data, password, opts)` | Password-based encryption |
|
|
244
|
+
| `decryptFileWithPassword(oqeBytes, password)` | Password-based decryption |
|
|
245
|
+
|
|
246
|
+
### Cryptographic Primitives
|
|
247
|
+
|
|
248
|
+
#### BLAKE3
|
|
249
|
+
```typescript
|
|
250
|
+
import { blake3, blake3Hex, blake3Mac, blake3DeriveKey } from '@omnituum/pqc-shared';
|
|
251
|
+
|
|
252
|
+
blake3(data); // 32-byte hash
|
|
253
|
+
blake3Hex(data); // Hex string
|
|
254
|
+
blake3Mac(key, data); // Keyed MAC
|
|
255
|
+
blake3DeriveKey(ikm, 'context'); // Key derivation
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
#### ChaCha20-Poly1305
|
|
259
|
+
```typescript
|
|
260
|
+
import {
|
|
261
|
+
chaCha20Poly1305Encrypt,
|
|
262
|
+
chaCha20Poly1305Decrypt,
|
|
263
|
+
xChaCha20Poly1305Encrypt,
|
|
264
|
+
xChaCha20Poly1305Decrypt,
|
|
265
|
+
} from '@omnituum/pqc-shared';
|
|
266
|
+
|
|
267
|
+
// 12-byte nonce
|
|
268
|
+
const ciphertext = chaCha20Poly1305Encrypt(key, nonce12, plaintext, aad?);
|
|
269
|
+
const plaintext = chaCha20Poly1305Decrypt(key, nonce12, ciphertext, aad?);
|
|
270
|
+
|
|
271
|
+
// 24-byte nonce (extended)
|
|
272
|
+
const ciphertext = xChaCha20Poly1305Encrypt(key, nonce24, plaintext, aad?);
|
|
273
|
+
const plaintext = xChaCha20Poly1305Decrypt(key, nonce24, ciphertext, aad?);
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
#### HKDF
|
|
277
|
+
```typescript
|
|
278
|
+
import { hkdfDerive, hkdfExtract, hkdfExpand } from '@omnituum/pqc-shared';
|
|
279
|
+
|
|
280
|
+
const key = hkdfDerive(ikm, salt, info, 32); // Full HKDF
|
|
281
|
+
const prk = hkdfExtract(ikm, salt); // Extract phase
|
|
282
|
+
const okm = hkdfExpand(prk, info, 32); // Expand phase
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
#### NaCl SecretBox
|
|
286
|
+
```typescript
|
|
287
|
+
import {
|
|
288
|
+
secretboxEncrypt,
|
|
289
|
+
secretboxDecrypt,
|
|
290
|
+
SECRETBOX_KEY_SIZE, // 32
|
|
291
|
+
SECRETBOX_NONCE_SIZE, // 24
|
|
292
|
+
} from '@omnituum/pqc-shared';
|
|
293
|
+
|
|
294
|
+
const { nonce, ciphertext } = secretboxEncrypt(key, plaintext);
|
|
295
|
+
const plaintext = secretboxDecrypt(key, nonce, ciphertext);
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
### Security Utilities
|
|
299
|
+
|
|
300
|
+
```typescript
|
|
301
|
+
import {
|
|
302
|
+
SecureBuffer,
|
|
303
|
+
zeroMemory,
|
|
304
|
+
zeroAll,
|
|
305
|
+
withSecureData,
|
|
306
|
+
constantTimeEqual,
|
|
307
|
+
} from '@omnituum/pqc-shared';
|
|
308
|
+
|
|
309
|
+
// Memory cleanup
|
|
310
|
+
zeroMemory(sensitiveArray);
|
|
311
|
+
zeroAll(array1, array2, array3);
|
|
312
|
+
|
|
313
|
+
// Secure data handling
|
|
314
|
+
const result = withSecureData(
|
|
315
|
+
() => getSensitiveKey(),
|
|
316
|
+
(key) => doOperation(key)
|
|
317
|
+
); // Key is zeroed after callback
|
|
318
|
+
|
|
319
|
+
// Timing-safe comparison
|
|
320
|
+
if (constantTimeEqual(hash1, hash2)) { ... }
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
### Encoding Utilities
|
|
324
|
+
|
|
325
|
+
```typescript
|
|
326
|
+
import { toB64, fromB64, toHex, fromHex, rand32 } from '@omnituum/pqc-shared';
|
|
327
|
+
|
|
328
|
+
toB64(bytes); // Uint8Array → base64 string
|
|
329
|
+
fromB64(str); // base64 string → Uint8Array
|
|
330
|
+
toHex(bytes); // Uint8Array → hex string
|
|
331
|
+
fromHex(str); // hex string → Uint8Array
|
|
332
|
+
|
|
333
|
+
rand32(); // 32 random bytes
|
|
334
|
+
rand24(); // 24 random bytes
|
|
335
|
+
rand12(); // 12 random bytes
|
|
336
|
+
randN(n); // n random bytes
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
---
|
|
340
|
+
|
|
341
|
+
## Data Formats
|
|
342
|
+
|
|
343
|
+
### HybridIdentity
|
|
344
|
+
|
|
345
|
+
```typescript
|
|
346
|
+
interface HybridIdentity {
|
|
347
|
+
id: string; // Unique identifier
|
|
348
|
+
name: string; // Display name
|
|
349
|
+
x25519PubHex: string; // X25519 public key (hex)
|
|
350
|
+
x25519SecHex: string; // X25519 secret key (hex)
|
|
351
|
+
kyberPubB64: string; // Kyber public key (base64)
|
|
352
|
+
kyberSecB64: string; // Kyber secret key (base64)
|
|
353
|
+
createdAt: string; // ISO timestamp
|
|
354
|
+
lastRotatedAt?: string; // Key rotation timestamp
|
|
355
|
+
rotationCount: number; // Rotation counter
|
|
356
|
+
}
|
|
357
|
+
```
|
|
358
|
+
|
|
359
|
+
### HybridEnvelope
|
|
360
|
+
|
|
361
|
+
```typescript
|
|
362
|
+
interface HybridEnvelope {
|
|
363
|
+
v: string; // "omnituum.hybrid.v1"
|
|
364
|
+
suite: string; // "x25519+kyber768"
|
|
365
|
+
aead: string; // "xsalsa20poly1305"
|
|
366
|
+
x25519Epk: string; // Ephemeral X25519 public key
|
|
367
|
+
x25519Wrap: { nonce: string; wrapped: string };
|
|
368
|
+
kyberKemCt: string; // Kyber KEM ciphertext
|
|
369
|
+
kyberWrap: { nonce: string; wrapped: string };
|
|
370
|
+
contentNonce: string; // Content encryption nonce
|
|
371
|
+
ciphertext: string; // Encrypted content
|
|
372
|
+
meta: {
|
|
373
|
+
createdAt: string;
|
|
374
|
+
senderName?: string;
|
|
375
|
+
senderId?: string;
|
|
376
|
+
};
|
|
377
|
+
}
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
### OQE File Format
|
|
381
|
+
|
|
382
|
+
The `.oqe` (Omnituum Quantum Encrypted) format:
|
|
383
|
+
|
|
384
|
+
```
|
|
385
|
+
┌─────────────────────────────────────┐
|
|
386
|
+
│ Magic: 0x4F 0x51 0x45 0x46 ("OQEF") │
|
|
387
|
+
│ Version: 0x01 │
|
|
388
|
+
│ Mode: 0x01 (hybrid) | 0x02 (password)│
|
|
389
|
+
├─────────────────────────────────────┤
|
|
390
|
+
│ [Mode-specific key material] │
|
|
391
|
+
│ [Encrypted metadata] │
|
|
392
|
+
│ [Encrypted file content] │
|
|
393
|
+
└─────────────────────────────────────┘
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
---
|
|
397
|
+
|
|
398
|
+
## Version Constants
|
|
399
|
+
|
|
400
|
+
```typescript
|
|
401
|
+
import {
|
|
402
|
+
VAULT_VERSION, // "omnituum.vault.v1"
|
|
403
|
+
VAULT_ENCRYPTED_VERSION, // "omnituum.vault.enc.v1" (PBKDF2)
|
|
404
|
+
VAULT_ENCRYPTED_VERSION_V2, // "omnituum.vault.enc.v2" (Argon2id)
|
|
405
|
+
ENVELOPE_VERSION, // "omnituum.hybrid.v1"
|
|
406
|
+
ENVELOPE_SUITE, // "x25519+kyber768"
|
|
407
|
+
ENVELOPE_AEAD, // "xsalsa20poly1305"
|
|
408
|
+
} from '@omnituum/pqc-shared';
|
|
409
|
+
```
|
|
410
|
+
|
|
411
|
+
---
|
|
412
|
+
|
|
413
|
+
## Module Imports
|
|
414
|
+
|
|
415
|
+
The package supports tree-shaking via subpath exports:
|
|
416
|
+
|
|
417
|
+
```typescript
|
|
418
|
+
// Full library
|
|
419
|
+
import { ... } from '@omnituum/pqc-shared';
|
|
420
|
+
|
|
421
|
+
// Crypto only
|
|
422
|
+
import { ... } from '@omnituum/pqc-shared/crypto';
|
|
423
|
+
|
|
424
|
+
// Vault only
|
|
425
|
+
import { ... } from '@omnituum/pqc-shared/vault';
|
|
426
|
+
|
|
427
|
+
// File system / encryption
|
|
428
|
+
import { ... } from '@omnituum/pqc-shared/fs';
|
|
429
|
+
|
|
430
|
+
// Utilities
|
|
431
|
+
import { ... } from '@omnituum/pqc-shared/utils';
|
|
432
|
+
```
|
|
433
|
+
|
|
434
|
+
---
|
|
435
|
+
|
|
436
|
+
## Security Considerations
|
|
437
|
+
|
|
438
|
+
### Post-Quantum Security
|
|
439
|
+
|
|
440
|
+
This library implements post-quantum algorithms based on NIST standards:
|
|
441
|
+
|
|
442
|
+
- **ML-KEM-768** (FIPS 203) — Key encapsulation mechanism, via `kyber-crystals`
|
|
443
|
+
- **ML-DSA-65** (FIPS 204) — Digital signatures, via `@noble/post-quantum`
|
|
444
|
+
|
|
445
|
+
Hybrid encryption combines classical (X25519, RFC 7748) and post-quantum (ML-KEM) algorithms. Both must decrypt successfully, providing defense-in-depth.
|
|
446
|
+
|
|
447
|
+
> **Note:** This library is pre-audit. "Implements" means we use these algorithms via dependencies; it does not imply FIPS certification or compliance program participation.
|
|
448
|
+
|
|
449
|
+
### Key Derivation
|
|
450
|
+
|
|
451
|
+
| Version | KDF | Parameters |
|
|
452
|
+
|---------|-----|------------|
|
|
453
|
+
| V1 | PBKDF2-SHA256 | 600,000 iterations |
|
|
454
|
+
| V2 | Argon2id | 64MB memory, 3 iterations, parallelism 4 |
|
|
455
|
+
|
|
456
|
+
New implementations should use Argon2id (V2). Use `migrateEncryptedVault()` to upgrade legacy vaults.
|
|
457
|
+
|
|
458
|
+
### Memory Hygiene
|
|
459
|
+
|
|
460
|
+
Always zero sensitive data after use:
|
|
461
|
+
|
|
462
|
+
```typescript
|
|
463
|
+
import { zeroMemory, withSecureData } from '@omnituum/pqc-shared';
|
|
464
|
+
|
|
465
|
+
// Manual cleanup
|
|
466
|
+
const key = deriveKey(...);
|
|
467
|
+
try {
|
|
468
|
+
// use key
|
|
469
|
+
} finally {
|
|
470
|
+
zeroMemory(key);
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
// Automatic cleanup
|
|
474
|
+
withSecureData(
|
|
475
|
+
() => deriveKey(...),
|
|
476
|
+
(key) => encrypt(key, data)
|
|
477
|
+
);
|
|
478
|
+
```
|
|
479
|
+
|
|
480
|
+
### Timing Attacks
|
|
481
|
+
|
|
482
|
+
Use `constantTimeEqual()` for comparing secrets:
|
|
483
|
+
|
|
484
|
+
```typescript
|
|
485
|
+
import { constantTimeEqual } from '@omnituum/pqc-shared';
|
|
486
|
+
|
|
487
|
+
// Bad: variable-time comparison
|
|
488
|
+
if (hash1 === hash2) { ... }
|
|
489
|
+
|
|
490
|
+
// Good: constant-time comparison
|
|
491
|
+
if (constantTimeEqual(hash1, hash2)) { ... }
|
|
492
|
+
```
|
|
493
|
+
|
|
494
|
+
---
|
|
495
|
+
|
|
496
|
+
## Dependencies
|
|
497
|
+
|
|
498
|
+
| Package | Purpose |
|
|
499
|
+
|---------|---------|
|
|
500
|
+
| `@noble/ciphers` | ChaCha20-Poly1305 AEAD |
|
|
501
|
+
| `@noble/hashes` | SHA-256, BLAKE3, HMAC, HKDF |
|
|
502
|
+
| `@noble/post-quantum` | ML-DSA-65 (Dilithium) signatures |
|
|
503
|
+
| `hash-wasm` | Argon2id (WebAssembly) |
|
|
504
|
+
| `kyber-crystals` | ML-KEM-768 (Kyber) |
|
|
505
|
+
| `tweetnacl` | NaCl box/secretbox, X25519 |
|
|
506
|
+
|
|
507
|
+
All dependencies are pure JavaScript/WebAssembly with no native bindings.
|
|
508
|
+
|
|
509
|
+
---
|
|
510
|
+
|
|
511
|
+
## Development
|
|
512
|
+
|
|
513
|
+
```bash
|
|
514
|
+
# Build
|
|
515
|
+
pnpm build
|
|
516
|
+
|
|
517
|
+
# Watch mode
|
|
518
|
+
pnpm dev
|
|
519
|
+
|
|
520
|
+
# Type check
|
|
521
|
+
pnpm typecheck
|
|
522
|
+
|
|
523
|
+
# Run golden tests
|
|
524
|
+
pnpm test:golden
|
|
525
|
+
```
|
|
526
|
+
|
|
527
|
+
### Golden Tests
|
|
528
|
+
|
|
529
|
+
Test vectors in `tests/golden/` provide reproducible cryptographic test cases:
|
|
530
|
+
|
|
531
|
+
```bash
|
|
532
|
+
# Generate new test vectors (run once)
|
|
533
|
+
pnpm test:golden:generate
|
|
534
|
+
|
|
535
|
+
# Verify test vectors (CI/pre-audit)
|
|
536
|
+
pnpm test:golden:verify
|
|
537
|
+
```
|
|
538
|
+
|
|
539
|
+
---
|
|
540
|
+
|
|
541
|
+
## License
|
|
542
|
+
|
|
543
|
+
MIT
|