@dstorage-tech/dstorage-sdk 0.0.4 → 0.0.5

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 (55) hide show
  1. package/README.md +2 -0
  2. package/dist/browser.mjs +9 -8
  3. package/dist/index.js +8 -3
  4. package/dist/index.mjs +8 -3
  5. package/package.json +2 -1
  6. package/dist/KeypairEncryptionAdapter-AE75YC4W-AOWNSH2M.mjs +0 -9
  7. package/dist/KeypairEncryptionAdapter-AE75YC4W-BAVHRNNJ.mjs +0 -1
  8. package/dist/KeypairEncryptionAdapter-AE75YC4W-BEYO4RUO.mjs +0 -1
  9. package/dist/KeypairEncryptionAdapter-AE75YC4W-VAOH6AAL.mjs +0 -9
  10. package/dist/KeypairEncryptionAdapter-XUKCLRFU-6ERIZN2M.mjs +0 -1
  11. package/dist/MnemonicEncryptionAdapter-J6IE5OKA-6DFVUVD6.mjs +0 -1
  12. package/dist/MnemonicEncryptionAdapter-J6IE5OKA-O5AJPX42.mjs +0 -1
  13. package/dist/MnemonicEncryptionAdapter-J6IE5OKA-SI6TBLTQ.mjs +0 -9
  14. package/dist/MnemonicEncryptionAdapter-J6IE5OKA-WEPFOTSJ.mjs +0 -9
  15. package/dist/MnemonicEncryptionAdapter-RCHUETBP-ELAMJMMO.mjs +0 -1
  16. package/dist/PasswordEncryptionAdapter-CWOXUGR4-2YZ64B4A.mjs +0 -1
  17. package/dist/PasswordEncryptionAdapter-CWOXUGR4-DCEGC2NX.mjs +0 -1
  18. package/dist/PasswordEncryptionAdapter-CWOXUGR4-QEGGYPFJ.mjs +0 -13
  19. package/dist/PasswordEncryptionAdapter-CWOXUGR4-ZYUBUYUI.mjs +0 -13
  20. package/dist/PasswordEncryptionAdapter-ECHND672-XVBPHPPT.mjs +0 -1
  21. package/dist/chunk-4YMF57VY.mjs +0 -1
  22. package/dist/chunk-5MZ7FPPY.mjs +0 -1
  23. package/dist/chunk-5P4EW2YL.mjs +0 -1
  24. package/dist/chunk-5RW7SGA7.mjs +0 -1
  25. package/dist/chunk-62RSKZ6T.mjs +0 -118
  26. package/dist/chunk-BBJCQFWP.mjs +0 -275
  27. package/dist/chunk-EYF3263P.mjs +0 -2049
  28. package/dist/chunk-GUYENY5N.mjs +0 -1
  29. package/dist/chunk-L5QD6GHB.mjs +0 -101
  30. package/dist/chunk-PKHRAYFD.mjs +0 -1
  31. package/dist/chunk-PLAOCKSS.mjs +0 -101
  32. package/dist/chunk-QKA2DCR6.mjs +0 -118
  33. package/dist/chunk-RPSRFFXN.mjs +0 -275
  34. package/dist/chunk-TESUOXRJ.mjs +0 -1
  35. package/dist/chunk-TMLXCRJU.mjs +0 -1
  36. package/dist/chunk-TNRKN4LB.mjs +0 -1
  37. package/dist/chunk-TSZ37JDY.mjs +0 -2596
  38. package/dist/chunk-U3MS6KMF.mjs +0 -1
  39. package/dist/chunk-UBALMYIY.mjs +0 -2049
  40. package/dist/chunk-UOOF4V2Y.mjs +0 -1
  41. package/dist/chunk-Z2TH6U4C.mjs +0 -3
  42. package/dist/chunk-ZEPZ4QDD.mjs +0 -1
  43. package/dist/chunk-ZGUY5EIR.mjs +0 -1
  44. package/dist/contract-api-AO4RGPLT-4HRCMSCE.mjs +0 -279
  45. package/dist/contract-api-AO4RGPLT-ADH6ZDKC.mjs +0 -279
  46. package/dist/contract-api-AO4RGPLT-PAMIPEI3.mjs +0 -1
  47. package/dist/contract-api-AO4RGPLT-W3RSVP5A.mjs +0 -1
  48. package/dist/contract-api-AO4RGPLT-WENYDV6I.mjs +0 -1
  49. package/dist/contract-api-TJ7JPHZA-ZWP3EH7D.mjs +0 -279
  50. package/dist/dataregistry-simulator-E6RTGGWT-QGCYR3VF.mjs +0 -1
  51. package/dist/dist-655VYUPJ.mjs +0 -1
  52. package/dist/dist-MEZZWKP4.mjs +0 -1
  53. package/dist/dist-UD4WRMYJ.mjs +0 -65
  54. package/dist/esm5-AGBDHMNS.mjs +0 -1
  55. package/dist/in-memory-private-state-NGOP37V7-XFJFNFCQ.mjs +0 -1
@@ -1,275 +0,0 @@
1
- import {
2
- EncryptionErrorCode
3
- } from "./chunk-O37NHERH.mjs";
4
- import {
5
- DStorageError,
6
- deriveKek,
7
- unwrapKey,
8
- wrapKey
9
- } from "./chunk-BWLEAAFW.mjs";
10
-
11
- // ../encryption/dist/chunk-PDWRI7YP.mjs
12
- import { scrypt } from "@noble/hashes/scrypt.js";
13
- var KDF_PRESETS = {
14
- v1: { N: 131072, r: 8, p: 1 },
15
- "v1-lite": { N: 65536, r: 8, p: 1 }
16
- };
17
- var PasswordEncryptionAdapter = class _PasswordEncryptionAdapter {
18
- constructor(config) {
19
- this.name = "password";
20
- validatePassword(
21
- config.password,
22
- config.minPasswordLength ?? 12,
23
- config.minEntropyBits ?? 60,
24
- config.additionalValidators
25
- );
26
- this.salt = resolveSalt(config.salt);
27
- const resolved = resolveParams(config.preset, config.params);
28
- this.N = resolved.N;
29
- this.r = resolved.r;
30
- this.p = resolved.p;
31
- const passwordBytes = new TextEncoder().encode(config.password);
32
- const seed = scrypt(passwordBytes, this.salt, {
33
- N: this.N,
34
- r: this.r,
35
- p: this.p,
36
- dkLen: 64
37
- });
38
- this.kekMaterialPromise = globalThis.crypto.subtle.importKey("raw", seed, "HKDF", false, ["deriveBits"]).then(
39
- (key) => {
40
- seed.fill(0);
41
- return key;
42
- },
43
- (err) => {
44
- seed.fill(0);
45
- throw err;
46
- }
47
- );
48
- }
49
- /**
50
- * Reconstruct an adapter from parameters previously stored via `getKdfParams()`.
51
- * Use this when loading existing encrypted data — ensures the exact same N/r/p
52
- * are used regardless of what the current SDK defaults are.
53
- *
54
- * @example
55
- * const adapter = PasswordEncryptionAdapter.fromKdfParams({
56
- * password,
57
- * salt: meta.salt,
58
- * kdf: meta.kdf,
59
- * N: meta.N,
60
- * r: meta.r,
61
- * p: meta.p,
62
- * });
63
- */
64
- static fromKdfParams(config) {
65
- if (config.kdf !== "scrypt") {
66
- throw new DStorageError(
67
- EncryptionErrorCode.PASSWORD_UNSUPPORTED_KDF,
68
- `[dStorage] PasswordEncryptionAdapter.fromKdfParams: unsupported kdf "${config.kdf}". Only "scrypt" is supported.`
69
- );
70
- }
71
- return new _PasswordEncryptionAdapter({
72
- password: config.password,
73
- salt: config.salt,
74
- params: { N: config.N, r: config.r, p: config.p },
75
- ...config.minPasswordLength !== void 0 && {
76
- minPasswordLength: config.minPasswordLength
77
- },
78
- ...config.minEntropyBits !== void 0 && {
79
- minEntropyBits: config.minEntropyBits
80
- },
81
- ...config.additionalValidators !== void 0 && {
82
- additionalValidators: config.additionalValidators
83
- }
84
- });
85
- }
86
- /**
87
- * Returns the resolved KDF parameters to store alongside encrypted data.
88
- *
89
- * These values are language- and SDK-agnostic: any scrypt implementation
90
- * can re-derive the key from `{ kdf, N, r, p }` + the original salt and
91
- * password, without any knowledge of this SDK's preset names.
92
- *
93
- * @example
94
- * const meta = {
95
- * ...adapter.getKdfParams(), // { kdf: "scrypt", N: 131072, r: 8, p: 1 }
96
- * salt: "myapp:alice@example.com",
97
- * };
98
- * await db.save({ encryptedData, meta });
99
- */
100
- getKdfParams() {
101
- return { kdf: "scrypt", N: this.N, r: this.r, p: this.p };
102
- }
103
- async wrapDek(dek) {
104
- const kekMaterial = await this.kekMaterialPromise;
105
- const kek = await deriveKek(kekMaterial);
106
- try {
107
- return {
108
- algorithm: "xchacha20poly1305-v1",
109
- kekDerivation: "hkdf-sha256-v1",
110
- wrappedDek: await wrapKey(dek, kek)
111
- };
112
- } finally {
113
- kek.fill(0);
114
- }
115
- }
116
- async unwrapDek({ wrappedDek }) {
117
- const kekMaterial = await this.kekMaterialPromise;
118
- const kek = await deriveKek(kekMaterial);
119
- try {
120
- return unwrapKey(wrappedDek, kek);
121
- } finally {
122
- kek.fill(0);
123
- }
124
- }
125
- /**
126
- * Deterministically derive a ML-KEM keypair from this adapter's key material.
127
- *
128
- * Uses Web Crypto HKDF to derive a 64-byte ML-KEM seed from the stored
129
- * CryptoKey, domain-separated from the symmetric KEK derivation path with
130
- * info="dstorage:mlkem-seed:v1". This is equivalent to noble's
131
- * hkdf(sha256, scryptOutput, undefined, info, 64) but avoids materialising
132
- * the raw scrypt output in a JS-accessible variable.
133
- *
134
- * Same password + salt + variant always produces the same keypair.
135
- *
136
- * @param variant ML-KEM variant. Default: "mlkem768".
137
- */
138
- async intoKeypairEncryptionAdapter(context, variant) {
139
- const { KeypairEncryptionAdapter } = await import("./KeypairEncryptionAdapter-AE75YC4W-VAOH6AAL.mjs");
140
- const { mlkemGenerateKeypairFromSeed } = await import("./dist-INTAFXQ7.mjs");
141
- const kekMaterial = await this.kekMaterialPromise;
142
- const mlkemBits = await globalThis.crypto.subtle.deriveBits(
143
- {
144
- name: "HKDF",
145
- hash: "SHA-256",
146
- salt: new Uint8Array(32),
147
- info: new TextEncoder().encode("dstorage:mlkem-seed:v1")
148
- },
149
- kekMaterial,
150
- 512
151
- // 64 bytes
152
- );
153
- const mlkemSeed = new Uint8Array(mlkemBits);
154
- try {
155
- const { pk, sk } = mlkemGenerateKeypairFromSeed(mlkemSeed, variant);
156
- return KeypairEncryptionAdapter.fromKeypair(pk, sk, context, variant);
157
- } finally {
158
- mlkemSeed.fill(0);
159
- }
160
- }
161
- };
162
- function resolveSalt(salt) {
163
- const bytes = typeof salt === "string" ? new TextEncoder().encode(salt) : salt;
164
- if (bytes.length === 0) {
165
- throw new DStorageError(
166
- EncryptionErrorCode.PASSWORD_EMPTY_SALT,
167
- '[dStorage] PasswordEncryptionAdapter: salt must not be empty. Provide an app-specific domain label, e.g. "myapp:v1:alice@example.com".'
168
- );
169
- }
170
- return bytes;
171
- }
172
- function resolveParams(preset, params) {
173
- if (preset !== void 0) {
174
- if (!(preset in KDF_PRESETS)) {
175
- throw new DStorageError(
176
- EncryptionErrorCode.PASSWORD_UNKNOWN_PRESET,
177
- `[dStorage] PasswordEncryptionAdapter: unknown preset "${preset}". Valid presets: ${Object.keys(KDF_PRESETS).join(", ")}.`
178
- );
179
- }
180
- return KDF_PRESETS[preset];
181
- }
182
- return {
183
- N: params?.N ?? KDF_PRESETS["v1"].N,
184
- r: params?.r ?? KDF_PRESETS["v1"].r,
185
- p: params?.p ?? KDF_PRESETS["v1"].p
186
- };
187
- }
188
- function estimateEntropyBits(password) {
189
- let pool = 0;
190
- if (/[a-z]/.test(password)) pool += 26;
191
- if (/[A-Z]/.test(password)) pool += 26;
192
- if (/[0-9]/.test(password)) pool += 10;
193
- if (/[^a-zA-Z0-9]/.test(password)) pool += 32;
194
- return pool === 0 ? 0 : Math.log2(pool) * password.length;
195
- }
196
- function hasSequentialRun(pw, runLength = 5) {
197
- for (let i = 0; i <= pw.length - runLength; i++) {
198
- let ascending = true;
199
- let descending = true;
200
- for (let j = 1; j < runLength; j++) {
201
- const diff = pw.charCodeAt(i + j) - pw.charCodeAt(i + j - 1);
202
- if (diff !== 1) ascending = false;
203
- if (diff !== -1) descending = false;
204
- if (!ascending && !descending) break;
205
- }
206
- if (ascending || descending) return true;
207
- }
208
- return false;
209
- }
210
- var KEYBOARD_ROWS = ["qwertyuiop", "asdfghjkl", "zxcvbnm", "1234567890"];
211
- function hasKeyboardWalk(pw, minLen = 5) {
212
- const lower = pw.toLowerCase();
213
- for (const row of KEYBOARD_ROWS) {
214
- for (let i = 0; i <= row.length - minLen; i++) {
215
- const fwd = row.slice(i, i + minLen);
216
- const rev = fwd.split("").reverse().join("");
217
- if (lower.includes(fwd) || lower.includes(rev)) return true;
218
- }
219
- }
220
- return false;
221
- }
222
- function generatePqsPassword() {
223
- while (true) {
224
- const bytes = globalThis.crypto.getRandomValues(new Uint8Array(32));
225
- const b64 = btoa(Array.from(bytes, (b) => String.fromCharCode(b)).join(""));
226
- const password = b64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
227
- if (new Set(password).size >= 3 && !hasSequentialRun(password) && !hasKeyboardWalk(password)) {
228
- return password;
229
- }
230
- }
231
- }
232
- function validatePassword(password, minLength, minEntropyBits, additionalValidators) {
233
- if (password.length < minLength) {
234
- throw new DStorageError(
235
- EncryptionErrorCode.PASSWORD_TOO_SHORT,
236
- `[dStorage] Password too short: ${password.length} character(s) (minimum ${minLength}). Use a longer passphrase.`
237
- );
238
- }
239
- if (new Set(password).size < 3) {
240
- throw new DStorageError(
241
- EncryptionErrorCode.PASSWORD_TOO_FEW_DISTINCT,
242
- "[dStorage] Password is too weak: too few distinct characters."
243
- );
244
- }
245
- if (hasSequentialRun(password)) {
246
- throw new DStorageError(
247
- EncryptionErrorCode.PASSWORD_SEQUENTIAL_RUN,
248
- "[dStorage] Password is too weak: contains a sequential character run (e.g. abcde, 12345)."
249
- );
250
- }
251
- if (hasKeyboardWalk(password)) {
252
- throw new DStorageError(
253
- EncryptionErrorCode.PASSWORD_KEYBOARD_WALK,
254
- "[dStorage] Password is too weak: contains a keyboard-row pattern (e.g. qwerty, asdfg)."
255
- );
256
- }
257
- const entropy = estimateEntropyBits(password);
258
- if (entropy < minEntropyBits) {
259
- throw new DStorageError(
260
- EncryptionErrorCode.PASSWORD_ENTROPY_TOO_LOW,
261
- `[dStorage] Password entropy too low: ~${Math.round(entropy)} bits (minimum ${minEntropyBits} bits). Use a longer password with a mix of uppercase, lowercase, digits, and symbols.`
262
- );
263
- }
264
- if (additionalValidators) {
265
- for (const validate of additionalValidators) {
266
- validate(password);
267
- }
268
- }
269
- }
270
-
271
- export {
272
- KDF_PRESETS,
273
- PasswordEncryptionAdapter,
274
- generatePqsPassword
275
- };