@enbox/dwn-sdk-js 0.4.5 → 0.4.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/dist/browser.mjs +3 -3
- package/dist/browser.mjs.map +3 -3
- package/dist/esm/generated/precompiled-validators.js +2700 -2576
- package/dist/esm/generated/precompiled-validators.js.map +1 -1
- package/dist/esm/src/utils/encryption.js +45 -25
- package/dist/esm/src/utils/encryption.js.map +1 -1
- package/dist/esm/tests/utils/encryption.spec.js +42 -62
- package/dist/esm/tests/utils/encryption.spec.js.map +1 -1
- package/dist/esm/tests/validation/json-schemas/encryption/audience-key.spec.js +40 -0
- package/dist/esm/tests/validation/json-schemas/encryption/audience-key.spec.js.map +1 -0
- package/dist/esm/tests/validation/json-schemas/encryption/grant-key.spec.js +25 -16
- package/dist/esm/tests/validation/json-schemas/encryption/grant-key.spec.js.map +1 -1
- package/dist/types/generated/precompiled-validators.d.ts.map +1 -1
- package/dist/types/src/utils/encryption.d.ts +7 -0
- package/dist/types/src/utils/encryption.d.ts.map +1 -1
- package/dist/types/tests/validation/json-schemas/encryption/audience-key.spec.d.ts +2 -0
- package/dist/types/tests/validation/json-schemas/encryption/audience-key.spec.d.ts.map +1 -0
- package/package.json +1 -1
- package/src/utils/encryption.ts +81 -33
package/src/utils/encryption.ts
CHANGED
|
@@ -44,6 +44,8 @@ export type RoleAudienceKeyEncryption = {
|
|
|
44
44
|
|
|
45
45
|
export type KeyEncryption = ProtocolPathKeyEncryption | RoleAudienceKeyEncryption;
|
|
46
46
|
|
|
47
|
+
export type X25519KeyEncryption = ProtocolPathKeyEncryption | RoleAudienceKeyEncryption;
|
|
48
|
+
|
|
47
49
|
export type DwnEncryption = {
|
|
48
50
|
algorithm: ContentEncryptionAlgorithm.A256CTR;
|
|
49
51
|
initializationVector: string;
|
|
@@ -67,6 +69,8 @@ export type RoleAudienceKeyEncryptionInput = {
|
|
|
67
69
|
|
|
68
70
|
export type KeyEncryptionInput = ProtocolPathKeyEncryptionInput | RoleAudienceKeyEncryptionInput;
|
|
69
71
|
|
|
72
|
+
export type X25519KeyEncryptionInput = ProtocolPathKeyEncryptionInput | RoleAudienceKeyEncryptionInput;
|
|
73
|
+
|
|
70
74
|
export type EncryptionInput = {
|
|
71
75
|
algorithm?: ContentEncryptionAlgorithm;
|
|
72
76
|
key: Uint8Array;
|
|
@@ -138,6 +142,15 @@ export class Encryption {
|
|
|
138
142
|
cek: Uint8Array,
|
|
139
143
|
keyInput: KeyEncryptionInput,
|
|
140
144
|
ephemeralPrivateKey?: Jwk,
|
|
145
|
+
): Promise<{ encryptedKey: Uint8Array; ephemeralPublicKey: PublicKeyJwk }> {
|
|
146
|
+
return Encryption.wrapX25519Key(recipientPublicKey, cek, keyInput, ephemeralPrivateKey);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
private static async wrapX25519Key(
|
|
150
|
+
recipientPublicKey: PublicKeyJwk,
|
|
151
|
+
cek: Uint8Array,
|
|
152
|
+
keyInput: X25519KeyEncryptionInput,
|
|
153
|
+
ephemeralPrivateKey?: Jwk,
|
|
141
154
|
): Promise<{ encryptedKey: Uint8Array; ephemeralPublicKey: PublicKeyJwk }> {
|
|
142
155
|
Encryption.validateContentEncryptionKey(cek);
|
|
143
156
|
|
|
@@ -158,6 +171,17 @@ export class Encryption {
|
|
|
158
171
|
public static async unwrapKey(
|
|
159
172
|
recipientPrivateKey: Jwk,
|
|
160
173
|
keyEncryption: KeyEncryption,
|
|
174
|
+
): Promise<Uint8Array> {
|
|
175
|
+
if (keyEncryption.algorithm === KeyAgreementAlgorithm.X25519HkdfSha256A256Kw) {
|
|
176
|
+
return Encryption.unwrapX25519Key(recipientPrivateKey, keyEncryption);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
throw new Error(`Unsupported key agreement algorithm: ${(keyEncryption as KeyEncryption).algorithm}`);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
private static async unwrapX25519Key(
|
|
183
|
+
recipientPrivateKey: Jwk,
|
|
184
|
+
keyEncryption: X25519KeyEncryption,
|
|
161
185
|
): Promise<Uint8Array> {
|
|
162
186
|
const sharedSecret = await X25519.sharedSecret({
|
|
163
187
|
privateKeyA : recipientPrivateKey,
|
|
@@ -182,31 +206,7 @@ export class Encryption {
|
|
|
182
206
|
|
|
183
207
|
const keyEncryption: KeyEncryption[] = [];
|
|
184
208
|
for (const keyInput of encryptionInput.keyEncryptionInputs) {
|
|
185
|
-
|
|
186
|
-
keyInput.publicKey,
|
|
187
|
-
encryptionInput.key,
|
|
188
|
-
keyInput,
|
|
189
|
-
);
|
|
190
|
-
const common = {
|
|
191
|
-
algorithm : KeyAgreementAlgorithm.X25519HkdfSha256A256Kw,
|
|
192
|
-
encryptedKey : Encoder.bytesToBase64Url(encryptedKey),
|
|
193
|
-
ephemeralPublicKey,
|
|
194
|
-
keyId : keyInput.keyId,
|
|
195
|
-
};
|
|
196
|
-
if (keyInput.derivationScheme === KeyDerivationScheme.ProtocolPath) {
|
|
197
|
-
keyEncryption.push({
|
|
198
|
-
...common,
|
|
199
|
-
derivationScheme: KeyDerivationScheme.ProtocolPath,
|
|
200
|
-
});
|
|
201
|
-
} else {
|
|
202
|
-
keyEncryption.push({
|
|
203
|
-
...common,
|
|
204
|
-
derivationScheme : ROLE_AUDIENCE_DERIVATION_SCHEME,
|
|
205
|
-
epoch : keyInput.epoch,
|
|
206
|
-
protocol : keyInput.protocol,
|
|
207
|
-
role : keyInput.role,
|
|
208
|
-
});
|
|
209
|
-
}
|
|
209
|
+
keyEncryption.push(await Encryption.buildKeyEncryptionEntry(encryptionInput.key, keyInput));
|
|
210
210
|
}
|
|
211
211
|
|
|
212
212
|
return {
|
|
@@ -230,18 +230,66 @@ export class Encryption {
|
|
|
230
230
|
}
|
|
231
231
|
|
|
232
232
|
for (const entry of encryption.keyEncryption) {
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
233
|
+
Encryption.validateKeyEncryptionEntry(entry);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
private static async buildKeyEncryptionEntry(
|
|
238
|
+
cek: Uint8Array,
|
|
239
|
+
keyInput: KeyEncryptionInput,
|
|
240
|
+
): Promise<KeyEncryption> {
|
|
241
|
+
const { encryptedKey, ephemeralPublicKey } = await Encryption.wrapKey(
|
|
242
|
+
keyInput.publicKey,
|
|
243
|
+
cek,
|
|
244
|
+
keyInput,
|
|
245
|
+
);
|
|
246
|
+
const common = {
|
|
247
|
+
algorithm : KeyAgreementAlgorithm.X25519HkdfSha256A256Kw,
|
|
248
|
+
encryptedKey : Encoder.bytesToBase64Url(encryptedKey),
|
|
249
|
+
ephemeralPublicKey,
|
|
250
|
+
keyId : keyInput.keyId,
|
|
251
|
+
};
|
|
252
|
+
|
|
253
|
+
if (keyInput.derivationScheme === KeyDerivationScheme.ProtocolPath) {
|
|
254
|
+
return {
|
|
255
|
+
...common,
|
|
256
|
+
derivationScheme: KeyDerivationScheme.ProtocolPath,
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
return {
|
|
261
|
+
...common,
|
|
262
|
+
derivationScheme : ROLE_AUDIENCE_DERIVATION_SCHEME,
|
|
263
|
+
epoch : keyInput.epoch,
|
|
264
|
+
protocol : keyInput.protocol,
|
|
265
|
+
role : keyInput.role,
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
private static validateKeyEncryptionEntry(entry: KeyEncryption): void {
|
|
270
|
+
if (entry.algorithm === KeyAgreementAlgorithm.X25519HkdfSha256A256Kw) {
|
|
271
|
+
Encryption.validateX25519KeyEncryptionEntry(entry);
|
|
272
|
+
return;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
throw new DwnError(
|
|
276
|
+
DwnErrorCode.RecordsWriteValidateIntegrityEncryptionEphemeralPublicKeyInvalid,
|
|
277
|
+
`Unsupported key agreement algorithm: ${(entry as KeyEncryption).algorithm}`
|
|
278
|
+
);
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
private static validateX25519KeyEncryptionEntry(entry: X25519KeyEncryption): void {
|
|
282
|
+
if (entry.ephemeralPublicKey.kty !== 'OKP' || entry.ephemeralPublicKey.crv !== 'X25519') {
|
|
283
|
+
throw new DwnError(
|
|
284
|
+
DwnErrorCode.RecordsWriteValidateIntegrityEncryptionEphemeralPublicKeyInvalid,
|
|
285
|
+
'ephemeralPublicKey must be an OKP X25519 public key.'
|
|
286
|
+
);
|
|
239
287
|
}
|
|
240
288
|
}
|
|
241
289
|
|
|
242
290
|
private static async deriveKek(
|
|
243
291
|
sharedSecret: Uint8Array,
|
|
244
|
-
keyEncryption:
|
|
292
|
+
keyEncryption: X25519KeyEncryptionInput | X25519KeyEncryption,
|
|
245
293
|
): Promise<Uint8Array> {
|
|
246
294
|
Encryption.validateSharedSecret(sharedSecret);
|
|
247
295
|
const info = Encryption.getKekInfo(keyEncryption);
|
|
@@ -254,7 +302,7 @@ export class Encryption {
|
|
|
254
302
|
});
|
|
255
303
|
}
|
|
256
304
|
|
|
257
|
-
private static getKekInfo(keyEncryption:
|
|
305
|
+
private static getKekInfo(keyEncryption: X25519KeyEncryptionInput | X25519KeyEncryption): string {
|
|
258
306
|
if (keyEncryption.derivationScheme === ROLE_AUDIENCE_DERIVATION_SCHEME) {
|
|
259
307
|
return `${KEK_INFO_PREFIX}|roleAudience|${keyEncryption.protocol}|${keyEncryption.role}|${keyEncryption.epoch}|${keyEncryption.keyId}`;
|
|
260
308
|
}
|