@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.
- package/README.md +2 -0
- package/dist/browser.mjs +9 -8
- package/dist/index.js +8 -3
- package/dist/index.mjs +8 -3
- package/package.json +2 -1
- package/dist/KeypairEncryptionAdapter-AE75YC4W-AOWNSH2M.mjs +0 -9
- package/dist/KeypairEncryptionAdapter-AE75YC4W-BAVHRNNJ.mjs +0 -1
- package/dist/KeypairEncryptionAdapter-AE75YC4W-BEYO4RUO.mjs +0 -1
- package/dist/KeypairEncryptionAdapter-AE75YC4W-VAOH6AAL.mjs +0 -9
- package/dist/KeypairEncryptionAdapter-XUKCLRFU-6ERIZN2M.mjs +0 -1
- package/dist/MnemonicEncryptionAdapter-J6IE5OKA-6DFVUVD6.mjs +0 -1
- package/dist/MnemonicEncryptionAdapter-J6IE5OKA-O5AJPX42.mjs +0 -1
- package/dist/MnemonicEncryptionAdapter-J6IE5OKA-SI6TBLTQ.mjs +0 -9
- package/dist/MnemonicEncryptionAdapter-J6IE5OKA-WEPFOTSJ.mjs +0 -9
- package/dist/MnemonicEncryptionAdapter-RCHUETBP-ELAMJMMO.mjs +0 -1
- package/dist/PasswordEncryptionAdapter-CWOXUGR4-2YZ64B4A.mjs +0 -1
- package/dist/PasswordEncryptionAdapter-CWOXUGR4-DCEGC2NX.mjs +0 -1
- package/dist/PasswordEncryptionAdapter-CWOXUGR4-QEGGYPFJ.mjs +0 -13
- package/dist/PasswordEncryptionAdapter-CWOXUGR4-ZYUBUYUI.mjs +0 -13
- package/dist/PasswordEncryptionAdapter-ECHND672-XVBPHPPT.mjs +0 -1
- package/dist/chunk-4YMF57VY.mjs +0 -1
- package/dist/chunk-5MZ7FPPY.mjs +0 -1
- package/dist/chunk-5P4EW2YL.mjs +0 -1
- package/dist/chunk-5RW7SGA7.mjs +0 -1
- package/dist/chunk-62RSKZ6T.mjs +0 -118
- package/dist/chunk-BBJCQFWP.mjs +0 -275
- package/dist/chunk-EYF3263P.mjs +0 -2049
- package/dist/chunk-GUYENY5N.mjs +0 -1
- package/dist/chunk-L5QD6GHB.mjs +0 -101
- package/dist/chunk-PKHRAYFD.mjs +0 -1
- package/dist/chunk-PLAOCKSS.mjs +0 -101
- package/dist/chunk-QKA2DCR6.mjs +0 -118
- package/dist/chunk-RPSRFFXN.mjs +0 -275
- package/dist/chunk-TESUOXRJ.mjs +0 -1
- package/dist/chunk-TMLXCRJU.mjs +0 -1
- package/dist/chunk-TNRKN4LB.mjs +0 -1
- package/dist/chunk-TSZ37JDY.mjs +0 -2596
- package/dist/chunk-U3MS6KMF.mjs +0 -1
- package/dist/chunk-UBALMYIY.mjs +0 -2049
- package/dist/chunk-UOOF4V2Y.mjs +0 -1
- package/dist/chunk-Z2TH6U4C.mjs +0 -3
- package/dist/chunk-ZEPZ4QDD.mjs +0 -1
- package/dist/chunk-ZGUY5EIR.mjs +0 -1
- package/dist/contract-api-AO4RGPLT-4HRCMSCE.mjs +0 -279
- package/dist/contract-api-AO4RGPLT-ADH6ZDKC.mjs +0 -279
- package/dist/contract-api-AO4RGPLT-PAMIPEI3.mjs +0 -1
- package/dist/contract-api-AO4RGPLT-W3RSVP5A.mjs +0 -1
- package/dist/contract-api-AO4RGPLT-WENYDV6I.mjs +0 -1
- package/dist/contract-api-TJ7JPHZA-ZWP3EH7D.mjs +0 -279
- package/dist/dataregistry-simulator-E6RTGGWT-QGCYR3VF.mjs +0 -1
- package/dist/dist-655VYUPJ.mjs +0 -1
- package/dist/dist-MEZZWKP4.mjs +0 -1
- package/dist/dist-UD4WRMYJ.mjs +0 -65
- package/dist/esm5-AGBDHMNS.mjs +0 -1
- package/dist/in-memory-private-state-NGOP37V7-XFJFNFCQ.mjs +0 -1
package/dist/chunk-BBJCQFWP.mjs
DELETED
|
@@ -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
|
-
};
|