@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.
@@ -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
- const { encryptedKey, ephemeralPublicKey } = await Encryption.wrapKey(
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
- if (entry.ephemeralPublicKey.kty !== 'OKP' || entry.ephemeralPublicKey.crv !== 'X25519') {
234
- throw new DwnError(
235
- DwnErrorCode.RecordsWriteValidateIntegrityEncryptionEphemeralPublicKeyInvalid,
236
- 'ephemeralPublicKey must be an OKP X25519 public key.'
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: KeyEncryptionInput | 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: KeyEncryptionInput | KeyEncryption): string {
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
  }