space-data-module-sdk 0.8.5 → 0.8.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/package.json +1 -1
- package/src/index.d.ts +10 -2
- package/src/transport/pki.js +57 -7
package/package.json
CHANGED
package/src/index.d.ts
CHANGED
|
@@ -855,9 +855,16 @@ export function protectMarketplaceContent(options: {
|
|
|
855
855
|
wrapNonce?: Uint8Array | ArrayBuffer | ArrayBufferView | number[] | null;
|
|
856
856
|
}): Promise<MarketplaceProtectedContent>;
|
|
857
857
|
|
|
858
|
+
export type KeyAgreementProvider = (params: {
|
|
859
|
+
ephemeralPublicKey: Uint8Array;
|
|
860
|
+
context: string;
|
|
861
|
+
keyExchange: string;
|
|
862
|
+
}) => Promise<Uint8Array>;
|
|
863
|
+
|
|
858
864
|
export function decryptMarketplaceContentKeyWrap(options: {
|
|
859
865
|
wrap: MarketplaceContentKeyWrap;
|
|
860
|
-
recipientPrivateKey
|
|
866
|
+
recipientPrivateKey?: Uint8Array | ArrayBuffer | ArrayBufferView | number[] | string;
|
|
867
|
+
keyAgreement?: KeyAgreementProvider;
|
|
861
868
|
}): Promise<Uint8Array>;
|
|
862
869
|
|
|
863
870
|
export function encryptBytesForRecipient(options: {
|
|
@@ -872,7 +879,8 @@ export function encryptBytesForRecipient(options: {
|
|
|
872
879
|
|
|
873
880
|
export function decryptProtectedBytes(options: {
|
|
874
881
|
protectedBytes: Uint8Array | ArrayBuffer;
|
|
875
|
-
recipientPrivateKey
|
|
882
|
+
recipientPrivateKey?: Uint8Array | string;
|
|
883
|
+
keyAgreement?: KeyAgreementProvider;
|
|
876
884
|
}): Promise<Uint8Array>;
|
|
877
885
|
|
|
878
886
|
export function decryptBytesFromEnvelope(options: {
|
package/src/transport/pki.js
CHANGED
|
@@ -80,6 +80,45 @@ async function deriveAesKey(sharedSecret, salt, context) {
|
|
|
80
80
|
);
|
|
81
81
|
}
|
|
82
82
|
|
|
83
|
+
// SAW-M3: the recipient's raw private scalar never has to enter this module.
|
|
84
|
+
// A caller (e.g. a browser session backed by hd-wallet-wasm) may supply a
|
|
85
|
+
// `keyAgreement` provider that performs step 1 (the X25519 ECDH, the ONLY
|
|
86
|
+
// step that needs the scalar) behind its own custody boundary and resolves
|
|
87
|
+
// the 32-byte shared secret. Steps 2-3 (HKDF derive, AES-GCM) stay here —
|
|
88
|
+
// public math, curve-agnostic, not duplicated into the wallet.
|
|
89
|
+
function keyExchangeFromAlgorithm(algorithm) {
|
|
90
|
+
if (typeof algorithm !== "string" || !algorithm.length) {
|
|
91
|
+
return "X25519";
|
|
92
|
+
}
|
|
93
|
+
return algorithm.split("-")[0] || "X25519";
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
async function resolveSharedSecret(
|
|
97
|
+
label,
|
|
98
|
+
{ recipientPrivateKey, keyAgreement, ephemeralPublicKey, context, keyExchange },
|
|
99
|
+
) {
|
|
100
|
+
if (recipientPrivateKey && keyAgreement) {
|
|
101
|
+
throw new Error(
|
|
102
|
+
`${label} accepts either recipientPrivateKey or keyAgreement, not both.`,
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
if (keyAgreement) {
|
|
106
|
+
const sharedSecret = toUint8Array(
|
|
107
|
+
await keyAgreement({ ephemeralPublicKey, context, keyExchange }),
|
|
108
|
+
);
|
|
109
|
+
if (sharedSecret.length !== 32) {
|
|
110
|
+
throw new Error(
|
|
111
|
+
`${label} keyAgreement provider must resolve a 32-byte shared secret.`,
|
|
112
|
+
);
|
|
113
|
+
}
|
|
114
|
+
return sharedSecret;
|
|
115
|
+
}
|
|
116
|
+
if (!recipientPrivateKey) {
|
|
117
|
+
throw new Error(`${label} requires recipientPrivateKey or keyAgreement.`);
|
|
118
|
+
}
|
|
119
|
+
return deriveSharedSecret(recipientPrivateKey, ephemeralPublicKey);
|
|
120
|
+
}
|
|
121
|
+
|
|
83
122
|
function normalizeOptionalBytes(value) {
|
|
84
123
|
if (value === null || value === undefined) {
|
|
85
124
|
return new Uint8Array(0);
|
|
@@ -308,15 +347,22 @@ export async function protectMarketplaceContent({
|
|
|
308
347
|
export async function decryptMarketplaceContentKeyWrap({
|
|
309
348
|
wrap,
|
|
310
349
|
recipientPrivateKey,
|
|
350
|
+
keyAgreement,
|
|
311
351
|
} = {}) {
|
|
312
352
|
if (!wrap) {
|
|
313
353
|
throw new Error("decryptMarketplaceContentKeyWrap requires wrap.");
|
|
314
354
|
}
|
|
315
|
-
const sharedSecret = await deriveSharedSecret(
|
|
316
|
-
recipientPrivateKey,
|
|
317
|
-
wrap.providerEphemeralPublicKey,
|
|
318
|
-
);
|
|
319
355
|
const wrapContext = `marketplace-content-key:${wrap.providerId}:${wrap.contentKeyId}:${wrap.recipientKeyId}`;
|
|
356
|
+
const sharedSecret = await resolveSharedSecret(
|
|
357
|
+
"decryptMarketplaceContentKeyWrap",
|
|
358
|
+
{
|
|
359
|
+
recipientPrivateKey,
|
|
360
|
+
keyAgreement,
|
|
361
|
+
ephemeralPublicKey: wrap.providerEphemeralPublicKey,
|
|
362
|
+
context: wrapContext,
|
|
363
|
+
keyExchange: keyExchangeFromAlgorithm(wrap.algorithm),
|
|
364
|
+
},
|
|
365
|
+
);
|
|
320
366
|
const wrapKey = await deriveAesKey(sharedSecret, new Uint8Array(0), wrapContext);
|
|
321
367
|
const keyMaterial = await aesGcmDecrypt(
|
|
322
368
|
wrapKey,
|
|
@@ -364,16 +410,20 @@ async function encryptBytesLegacy({
|
|
|
364
410
|
export async function decryptProtectedBytes({
|
|
365
411
|
protectedBytes,
|
|
366
412
|
recipientPrivateKey,
|
|
413
|
+
keyAgreement,
|
|
367
414
|
} = {}) {
|
|
368
415
|
const parsed = extractPublicationRecordCollection(protectedBytes);
|
|
369
416
|
if (!parsed?.enc) {
|
|
370
417
|
return toUint8Array(protectedBytes);
|
|
371
418
|
}
|
|
372
419
|
assertGcmEncRecord(parsed.enc);
|
|
373
|
-
const sharedSecret = await
|
|
420
|
+
const sharedSecret = await resolveSharedSecret("decryptProtectedBytes", {
|
|
374
421
|
recipientPrivateKey,
|
|
375
|
-
|
|
376
|
-
|
|
422
|
+
keyAgreement,
|
|
423
|
+
ephemeralPublicKey: parsed.enc.ephemeralPublicKey,
|
|
424
|
+
context: parsed.enc.context ?? "",
|
|
425
|
+
keyExchange: parsed.enc.keyExchange,
|
|
426
|
+
});
|
|
377
427
|
const aesKey = await deriveAesKey(
|
|
378
428
|
sharedSecret,
|
|
379
429
|
new Uint8Array(0),
|