@opentdf/sdk 0.9.0-beta.92 → 0.9.0-beta.94

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 (187) hide show
  1. package/README.md +2 -2
  2. package/dist/cjs/src/access/access-fetch.js +1 -2
  3. package/dist/cjs/src/access/access-rpc.js +1 -3
  4. package/dist/cjs/src/access.js +1 -14
  5. package/dist/cjs/src/auth/auth.js +13 -10
  6. package/dist/cjs/src/auth/dpop.js +121 -0
  7. package/dist/cjs/src/auth/oidc-clientcredentials-provider.js +37 -3
  8. package/dist/cjs/src/auth/oidc-externaljwt-provider.js +37 -3
  9. package/dist/cjs/src/auth/oidc-refreshtoken-provider.js +37 -3
  10. package/dist/cjs/src/auth/oidc.js +10 -8
  11. package/dist/cjs/src/auth/providers.js +35 -12
  12. package/dist/cjs/src/crypto/index.js +16 -2
  13. package/dist/cjs/src/crypto/pemPublicToCrypto.js +17 -11
  14. package/dist/cjs/src/opentdf.js +50 -13
  15. package/dist/cjs/src/policy/discovery.js +2 -2
  16. package/dist/cjs/tdf3/index.js +4 -2
  17. package/dist/cjs/tdf3/src/assertions.js +71 -31
  18. package/dist/cjs/tdf3/src/ciphers/aes-gcm-cipher.js +1 -1
  19. package/dist/cjs/tdf3/src/ciphers/symmetric-cipher-base.js +4 -2
  20. package/dist/cjs/tdf3/src/client/index.js +23 -33
  21. package/dist/cjs/tdf3/src/crypto/crypto-utils.js +12 -5
  22. package/dist/cjs/tdf3/src/crypto/declarations.js +1 -1
  23. package/dist/cjs/tdf3/src/crypto/index.js +849 -88
  24. package/dist/cjs/tdf3/src/crypto/jose/jwt-claims-set.js +11 -0
  25. package/dist/cjs/tdf3/src/crypto/jose/validate-crit.js +8 -0
  26. package/dist/cjs/tdf3/src/crypto/jose/vendor/lib/buffer_utils.js +41 -0
  27. package/dist/cjs/tdf3/src/crypto/jose/vendor/lib/epoch.js +6 -0
  28. package/dist/cjs/tdf3/src/crypto/jose/vendor/lib/is_object.js +21 -0
  29. package/dist/cjs/tdf3/src/crypto/jose/vendor/lib/jwt_claims_set.js +112 -0
  30. package/dist/cjs/tdf3/src/crypto/jose/vendor/lib/secs.js +60 -0
  31. package/dist/cjs/tdf3/src/crypto/jose/vendor/lib/validate_crit.js +38 -0
  32. package/dist/cjs/tdf3/src/crypto/jose/vendor/util/errors.js +135 -0
  33. package/dist/cjs/tdf3/src/crypto/jwt.js +183 -0
  34. package/dist/cjs/tdf3/src/crypto/salt.js +14 -8
  35. package/dist/cjs/tdf3/src/models/encryption-information.js +17 -20
  36. package/dist/cjs/tdf3/src/models/key-access.js +43 -63
  37. package/dist/cjs/tdf3/src/tdf.js +75 -75
  38. package/dist/cjs/tdf3/src/utils/index.js +5 -39
  39. package/dist/types/src/access/access-fetch.d.ts.map +1 -1
  40. package/dist/types/src/access/access-rpc.d.ts.map +1 -1
  41. package/dist/types/src/access.d.ts +0 -5
  42. package/dist/types/src/access.d.ts.map +1 -1
  43. package/dist/types/src/auth/auth.d.ts +9 -6
  44. package/dist/types/src/auth/auth.d.ts.map +1 -1
  45. package/dist/types/src/auth/dpop.d.ts +60 -0
  46. package/dist/types/src/auth/dpop.d.ts.map +1 -0
  47. package/dist/types/src/auth/oidc-clientcredentials-provider.d.ts +3 -2
  48. package/dist/types/src/auth/oidc-clientcredentials-provider.d.ts.map +1 -1
  49. package/dist/types/src/auth/oidc-externaljwt-provider.d.ts +3 -2
  50. package/dist/types/src/auth/oidc-externaljwt-provider.d.ts.map +1 -1
  51. package/dist/types/src/auth/oidc-refreshtoken-provider.d.ts +3 -2
  52. package/dist/types/src/auth/oidc-refreshtoken-provider.d.ts.map +1 -1
  53. package/dist/types/src/auth/oidc.d.ts +6 -4
  54. package/dist/types/src/auth/oidc.d.ts.map +1 -1
  55. package/dist/types/src/auth/providers.d.ts +5 -4
  56. package/dist/types/src/auth/providers.d.ts.map +1 -1
  57. package/dist/types/src/crypto/index.d.ts +2 -1
  58. package/dist/types/src/crypto/index.d.ts.map +1 -1
  59. package/dist/types/src/crypto/pemPublicToCrypto.d.ts +18 -0
  60. package/dist/types/src/crypto/pemPublicToCrypto.d.ts.map +1 -1
  61. package/dist/types/src/opentdf.d.ts +26 -7
  62. package/dist/types/src/opentdf.d.ts.map +1 -1
  63. package/dist/types/src/policy/discovery.d.ts +2 -2
  64. package/dist/types/tdf3/index.d.ts +3 -3
  65. package/dist/types/tdf3/index.d.ts.map +1 -1
  66. package/dist/types/tdf3/src/assertions.d.ts +23 -8
  67. package/dist/types/tdf3/src/assertions.d.ts.map +1 -1
  68. package/dist/types/tdf3/src/ciphers/aes-gcm-cipher.d.ts +3 -3
  69. package/dist/types/tdf3/src/ciphers/aes-gcm-cipher.d.ts.map +1 -1
  70. package/dist/types/tdf3/src/ciphers/symmetric-cipher-base.d.ts +4 -4
  71. package/dist/types/tdf3/src/ciphers/symmetric-cipher-base.d.ts.map +1 -1
  72. package/dist/types/tdf3/src/client/builders.d.ts +2 -2
  73. package/dist/types/tdf3/src/client/builders.d.ts.map +1 -1
  74. package/dist/types/tdf3/src/client/index.d.ts +6 -5
  75. package/dist/types/tdf3/src/client/index.d.ts.map +1 -1
  76. package/dist/types/tdf3/src/crypto/crypto-utils.d.ts +14 -4
  77. package/dist/types/tdf3/src/crypto/crypto-utils.d.ts.map +1 -1
  78. package/dist/types/tdf3/src/crypto/declarations.d.ts +283 -18
  79. package/dist/types/tdf3/src/crypto/declarations.d.ts.map +1 -1
  80. package/dist/types/tdf3/src/crypto/index.d.ts +105 -28
  81. package/dist/types/tdf3/src/crypto/index.d.ts.map +1 -1
  82. package/dist/types/tdf3/src/crypto/jose/jwt-claims-set.d.ts +3 -0
  83. package/dist/types/tdf3/src/crypto/jose/jwt-claims-set.d.ts.map +1 -0
  84. package/dist/types/tdf3/src/crypto/jose/validate-crit.d.ts +5 -0
  85. package/dist/types/tdf3/src/crypto/jose/validate-crit.d.ts.map +1 -0
  86. package/dist/types/tdf3/src/crypto/jose/vendor/lib/buffer_utils.d.ts +6 -0
  87. package/dist/types/tdf3/src/crypto/jose/vendor/lib/buffer_utils.d.ts.map +1 -0
  88. package/dist/types/tdf3/src/crypto/jose/vendor/lib/epoch.d.ts +3 -0
  89. package/dist/types/tdf3/src/crypto/jose/vendor/lib/epoch.d.ts.map +1 -0
  90. package/dist/types/tdf3/src/crypto/jose/vendor/lib/is_object.d.ts +3 -0
  91. package/dist/types/tdf3/src/crypto/jose/vendor/lib/is_object.d.ts.map +1 -0
  92. package/dist/types/tdf3/src/crypto/jose/vendor/lib/jwt_claims_set.d.ts +3 -0
  93. package/dist/types/tdf3/src/crypto/jose/vendor/lib/jwt_claims_set.d.ts.map +1 -0
  94. package/dist/types/tdf3/src/crypto/jose/vendor/lib/secs.d.ts +3 -0
  95. package/dist/types/tdf3/src/crypto/jose/vendor/lib/secs.d.ts.map +1 -0
  96. package/dist/types/tdf3/src/crypto/jose/vendor/lib/validate_crit.d.ts +3 -0
  97. package/dist/types/tdf3/src/crypto/jose/vendor/lib/validate_crit.d.ts.map +1 -0
  98. package/dist/types/tdf3/src/crypto/jose/vendor/util/errors.d.ts +76 -0
  99. package/dist/types/tdf3/src/crypto/jose/vendor/util/errors.d.ts.map +1 -0
  100. package/dist/types/tdf3/src/crypto/jwt.d.ts +76 -0
  101. package/dist/types/tdf3/src/crypto/jwt.d.ts.map +1 -0
  102. package/dist/types/tdf3/src/crypto/salt.d.ts +6 -1
  103. package/dist/types/tdf3/src/crypto/salt.d.ts.map +1 -1
  104. package/dist/types/tdf3/src/models/encryption-information.d.ts +4 -4
  105. package/dist/types/tdf3/src/models/encryption-information.d.ts.map +1 -1
  106. package/dist/types/tdf3/src/models/key-access.d.ts +8 -5
  107. package/dist/types/tdf3/src/models/key-access.d.ts.map +1 -1
  108. package/dist/types/tdf3/src/tdf.d.ts +8 -8
  109. package/dist/types/tdf3/src/tdf.d.ts.map +1 -1
  110. package/dist/types/tdf3/src/utils/index.d.ts +4 -3
  111. package/dist/types/tdf3/src/utils/index.d.ts.map +1 -1
  112. package/dist/web/src/access/access-fetch.js +3 -4
  113. package/dist/web/src/access/access-rpc.js +3 -5
  114. package/dist/web/src/access.js +1 -13
  115. package/dist/web/src/auth/auth.js +13 -10
  116. package/dist/web/src/auth/dpop.js +118 -0
  117. package/dist/web/src/auth/oidc-clientcredentials-provider.js +4 -3
  118. package/dist/web/src/auth/oidc-externaljwt-provider.js +4 -3
  119. package/dist/web/src/auth/oidc-refreshtoken-provider.js +4 -3
  120. package/dist/web/src/auth/oidc.js +11 -9
  121. package/dist/web/src/auth/providers.js +13 -12
  122. package/dist/web/src/crypto/index.js +4 -2
  123. package/dist/web/src/crypto/pemPublicToCrypto.js +11 -9
  124. package/dist/web/src/opentdf.js +17 -13
  125. package/dist/web/src/policy/discovery.js +2 -2
  126. package/dist/web/tdf3/index.js +3 -2
  127. package/dist/web/tdf3/src/assertions.js +71 -31
  128. package/dist/web/tdf3/src/ciphers/aes-gcm-cipher.js +1 -1
  129. package/dist/web/tdf3/src/ciphers/symmetric-cipher-base.js +4 -2
  130. package/dist/web/tdf3/src/client/index.js +25 -35
  131. package/dist/web/tdf3/src/crypto/crypto-utils.js +12 -5
  132. package/dist/web/tdf3/src/crypto/declarations.js +1 -1
  133. package/dist/web/tdf3/src/crypto/index.js +830 -84
  134. package/dist/web/tdf3/src/crypto/jose/jwt-claims-set.js +5 -0
  135. package/dist/web/tdf3/src/crypto/jose/validate-crit.js +3 -0
  136. package/dist/web/tdf3/src/crypto/jose/vendor/lib/buffer_utils.js +35 -0
  137. package/dist/web/tdf3/src/crypto/jose/vendor/lib/epoch.js +4 -0
  138. package/dist/web/tdf3/src/crypto/jose/vendor/lib/is_object.js +19 -0
  139. package/dist/web/tdf3/src/crypto/jose/vendor/lib/jwt_claims_set.js +107 -0
  140. package/dist/web/tdf3/src/crypto/jose/vendor/lib/secs.js +58 -0
  141. package/dist/web/tdf3/src/crypto/jose/vendor/lib/validate_crit.js +36 -0
  142. package/dist/web/tdf3/src/crypto/jose/vendor/util/errors.js +117 -0
  143. package/dist/web/tdf3/src/crypto/jwt.js +174 -0
  144. package/dist/web/tdf3/src/crypto/salt.js +13 -7
  145. package/dist/web/tdf3/src/models/encryption-information.js +11 -14
  146. package/dist/web/tdf3/src/models/key-access.js +44 -31
  147. package/dist/web/tdf3/src/tdf.js +71 -71
  148. package/dist/web/tdf3/src/utils/index.js +5 -6
  149. package/package.json +11 -4
  150. package/src/access/access-fetch.ts +2 -8
  151. package/src/access/access-rpc.ts +0 -7
  152. package/src/access.ts +0 -17
  153. package/src/auth/auth.ts +21 -12
  154. package/src/auth/dpop.ts +222 -0
  155. package/src/auth/oidc-clientcredentials-provider.ts +23 -15
  156. package/src/auth/oidc-externaljwt-provider.ts +23 -15
  157. package/src/auth/oidc-refreshtoken-provider.ts +23 -15
  158. package/src/auth/oidc.ts +21 -10
  159. package/src/auth/providers.ts +46 -29
  160. package/src/crypto/index.ts +21 -1
  161. package/src/crypto/pemPublicToCrypto.ts +11 -9
  162. package/src/opentdf.ts +36 -17
  163. package/src/policy/discovery.ts +2 -2
  164. package/tdf3/index.ts +32 -5
  165. package/tdf3/src/assertions.ts +99 -30
  166. package/tdf3/src/ciphers/aes-gcm-cipher.ts +7 -2
  167. package/tdf3/src/ciphers/symmetric-cipher-base.ts +7 -4
  168. package/tdf3/src/client/builders.ts +2 -2
  169. package/tdf3/src/client/index.ts +60 -59
  170. package/tdf3/src/crypto/crypto-utils.ts +15 -8
  171. package/tdf3/src/crypto/declarations.ts +338 -22
  172. package/tdf3/src/crypto/index.ts +1021 -118
  173. package/tdf3/src/crypto/jose/jwt-claims-set.ts +10 -0
  174. package/tdf3/src/crypto/jose/validate-crit.ts +9 -0
  175. package/tdf3/src/crypto/jose/vendor/lib/buffer_utils.ts +34 -0
  176. package/tdf3/src/crypto/jose/vendor/lib/epoch.ts +3 -0
  177. package/tdf3/src/crypto/jose/vendor/lib/is_object.ts +18 -0
  178. package/tdf3/src/crypto/jose/vendor/lib/jwt_claims_set.ts +106 -0
  179. package/tdf3/src/crypto/jose/vendor/lib/secs.ts +57 -0
  180. package/tdf3/src/crypto/jose/vendor/lib/validate_crit.ts +35 -0
  181. package/tdf3/src/crypto/jose/vendor/util/errors.ts +101 -0
  182. package/tdf3/src/crypto/jwt.ts +256 -0
  183. package/tdf3/src/crypto/salt.ts +16 -8
  184. package/tdf3/src/models/encryption-information.ts +14 -21
  185. package/tdf3/src/models/key-access.ts +57 -41
  186. package/tdf3/src/tdf.ts +110 -93
  187. package/tdf3/src/utils/index.ts +5 -6
package/tdf3/src/tdf.ts CHANGED
@@ -1,5 +1,3 @@
1
- import { exportSPKI, importX509 } from 'jose';
2
-
3
1
  import {
4
2
  KasPublicKeyAlgorithm,
5
3
  KasPublicKeyInfo,
@@ -29,9 +27,6 @@ import {
29
27
  UnsafeUrlError,
30
28
  UnsupportedFeatureError as UnsupportedError,
31
29
  } from '../../src/errors.js';
32
- import { generateKeyPair } from '../../src/crypto/generateKeyPair.js';
33
- import { keyAgreement } from '../../src/crypto/keyAgreement.js';
34
- import { pemPublicToCrypto } from '../../src/crypto/pemPublicToCrypto.js';
35
30
  import { type Chunker } from '../../src/seekable.js';
36
31
  import { tdfSpecVersion } from '../../src/version.js';
37
32
  import { AssertionConfig, AssertionKey, AssertionVerificationKeys } from './assertions.js';
@@ -42,11 +37,12 @@ import { SymmetricCipher } from './ciphers/symmetric-cipher-base.js';
42
37
  import { DecryptParams } from './client/builders.js';
43
38
  import { DecoratedReadableStream } from './client/DecoratedReadableStream.js';
44
39
  import {
45
- AnyKeyPair,
46
- PemKeyPair,
47
40
  type CryptoService,
48
41
  type DecryptResult,
42
+ type KeyPair,
43
+ type SymmetricKey,
49
44
  } from './crypto/declarations.js';
45
+ import { Algorithms } from './ciphers/index.js';
50
46
  import {
51
47
  ECWrapped,
52
48
  KeyAccessType,
@@ -60,9 +56,9 @@ import {
60
56
  SplitType,
61
57
  } from './models/index.js';
62
58
  import { unsigned } from './utils/buffer-crc32.js';
63
- import { ZipReader, ZipWriter, keyMerge, concatUint8, buffToString } from './utils/index.js';
59
+ import { ZipReader, ZipWriter, concatUint8, buffToString } from './utils/index.js';
64
60
  import { CentralDirectory } from './utils/zip-reader.js';
65
- import { ztdfSalt } from './crypto/salt.js';
61
+ import { getZtdfSalt } from './crypto/salt.js';
66
62
  import { Payload } from './models/payload.js';
67
63
  import {
68
64
  getRequiredObligationFQNs,
@@ -99,6 +95,7 @@ export type BuildKeyAccess = {
99
95
  publicKey: string;
100
96
  metadata?: Metadata;
101
97
  sid?: string;
98
+ cryptoService: CryptoService;
102
99
  };
103
100
 
104
101
  type Segment = {
@@ -147,7 +144,7 @@ export type IntegrityAlgorithm = 'GMAC' | 'HS256';
147
144
  export type EncryptConfiguration = {
148
145
  allowList?: OriginAllowList;
149
146
  cryptoService: CryptoService;
150
- dpopKeys: CryptoKeyPair;
147
+ dpopKeys: KeyPair;
151
148
  encryptionInformation: SplitKey;
152
149
  segmentSizeDefault: number;
153
150
  integrityAlgorithm: IntegrityAlgorithm;
@@ -172,7 +169,7 @@ export type DecryptConfiguration = {
172
169
  authProvider: AuthProvider;
173
170
  cryptoService: CryptoService;
174
171
 
175
- dpopKeys: CryptoKeyPair;
172
+ dpopKeys: KeyPair;
176
173
 
177
174
  chunker: Chunker;
178
175
  keyMiddleware: KeyMiddleware;
@@ -222,19 +219,13 @@ export async function fetchKasPublicKey(
222
219
 
223
220
  export async function extractPemFromKeyString(
224
221
  keyString: string,
225
- alg: KasPublicKeyAlgorithm
222
+ alg: KasPublicKeyAlgorithm,
223
+ cryptoService: CryptoService
226
224
  ): Promise<string> {
227
- let pem: string = keyString;
228
-
229
- // Skip the public key extraction if we find that the KAS url provides a
230
- // PEM-encoded key instead of certificate
231
- if (keyString.includes('CERTIFICATE')) {
232
- const a = publicKeyAlgorithmToJwa(alg);
233
- const cert = await importX509(keyString, a, { extractable: true });
234
- pem = await exportSPKI(cert);
235
- }
236
-
237
- return pem;
225
+ // Convert KAS algorithm to JWA algorithm if provided
226
+ const jwaAlgorithm = publicKeyAlgorithmToJwa(alg);
227
+ // extractPublicKeyPem handles both X.509 certificates and raw PEM keys
228
+ return cryptoService.extractPublicKeyPem(keyString, jwaAlgorithm);
238
229
  }
239
230
 
240
231
  /**
@@ -258,6 +249,7 @@ export async function buildKeyAccess({
258
249
  metadata,
259
250
  sid = '',
260
251
  alg = 'rsa:2048',
252
+ cryptoService,
261
253
  }: BuildKeyAccess): Promise<KeyAccess> {
262
254
  // if url and pulicKey are specified load the key access object with them
263
255
  if (!url && !publicKey) {
@@ -270,7 +262,7 @@ export async function buildKeyAccess({
270
262
 
271
263
  let pubKey: string;
272
264
  try {
273
- pubKey = await extractPemFromKeyString(publicKey, alg);
265
+ pubKey = await extractPemFromKeyString(publicKey, alg, cryptoService);
274
266
  } catch (e) {
275
267
  throw new ConfigurationError(
276
268
  `TDF.buildKeyAccess: Invalid public key [${publicKey}], caused by [${e}]`,
@@ -279,9 +271,9 @@ export async function buildKeyAccess({
279
271
  }
280
272
  switch (type) {
281
273
  case 'wrapped':
282
- return new Wrapped(url, kid, pubKey, metadata, sid);
274
+ return new Wrapped(url, kid, pubKey, metadata, cryptoService, sid);
283
275
  case 'ec-wrapped':
284
- return new ECWrapped(url, kid, pubKey, metadata, sid);
276
+ return new ECWrapped(url, kid, pubKey, metadata, cryptoService, sid);
285
277
  default:
286
278
  throw new ConfigurationError(`buildKeyAccess: Key access type [${type}] is unsupported`);
287
279
  }
@@ -336,28 +328,18 @@ async function _generateManifest(
336
328
  }
337
329
 
338
330
  async function getSignature(
339
- unwrappedKey: Uint8Array,
331
+ unwrappedKey: SymmetricKey,
340
332
  content: Uint8Array,
341
- algorithmType: IntegrityAlgorithm
333
+ algorithmType: IntegrityAlgorithm,
334
+ cryptoService: CryptoService
342
335
  ): Promise<Uint8Array> {
343
336
  switch (algorithmType.toUpperCase()) {
344
337
  case 'GMAC':
345
338
  // use the auth tag baked into the encrypted payload
346
339
  return content.slice(-16);
347
340
  case 'HS256': {
348
- // simple hmac is the default
349
- const cryptoKey = await crypto.subtle.importKey(
350
- 'raw',
351
- unwrappedKey,
352
- {
353
- name: 'HMAC',
354
- hash: { name: 'SHA-256' },
355
- },
356
- true,
357
- ['sign', 'verify']
358
- );
359
- const signature = await crypto.subtle.sign('HMAC', cryptoKey, content);
360
- return new Uint8Array(signature);
341
+ // Use CryptoService for HMAC-SHA256 signing
342
+ return cryptoService.hmac(content, unwrappedKey);
361
343
  }
362
344
  default:
363
345
  throw new ConfigurationError(`Unsupported signature alg [${algorithmType}]`);
@@ -365,7 +347,7 @@ async function getSignature(
365
347
  }
366
348
 
367
349
  async function getSignatureVersion422(
368
- unwrappedKeyBinary: Binary,
350
+ unwrappedKey: SymmetricKey,
369
351
  payloadBinary: Binary,
370
352
  algorithmType: IntegrityAlgorithm,
371
353
  cryptoService: CryptoService
@@ -374,11 +356,11 @@ async function getSignatureVersion422(
374
356
  case 'GMAC':
375
357
  // use the auth tag baked into the encrypted payload
376
358
  return buffToString(Uint8Array.from(payloadBinary.asByteArray()).slice(-16), 'hex');
377
- case 'HS256':
378
- return await cryptoService.hmac(
379
- buffToString(new Uint8Array(unwrappedKeyBinary.asArrayBuffer()), 'hex'),
380
- buffToString(new Uint8Array(payloadBinary.asArrayBuffer()), 'utf-8')
381
- );
359
+ case 'HS256': {
360
+ const content = buffToString(new Uint8Array(payloadBinary.asArrayBuffer()), 'utf-8');
361
+ const sig = await cryptoService.hmac(new TextEncoder().encode(content), unwrappedKey);
362
+ return hex.encodeArrayBuffer(sig.buffer);
363
+ }
382
364
  default:
383
365
  throw new ConfigurationError(`Unsupported signature alg [${algorithmType}]`);
384
366
  }
@@ -437,7 +419,7 @@ export async function writeStream(cfg: EncryptConfiguration): Promise<DecoratedR
437
419
  const { segmentSizeDefault } = cfg;
438
420
  const encryptedBlargh = await cfg.encryptionInformation.encrypt(
439
421
  Binary.fromArrayBuffer(new ArrayBuffer(segmentSizeDefault)),
440
- cfg.keyForEncryption.unwrappedKeyBinary
422
+ cfg.keyForEncryption.unwrappedKey
441
423
  );
442
424
  const payloadBuffer = new Uint8Array(encryptedBlargh.payload.asByteArray());
443
425
  const encryptedSegmentSizeDefault = payloadBuffer.length;
@@ -514,7 +496,7 @@ export async function writeStream(cfg: EncryptConfiguration): Promise<DecoratedR
514
496
  if (isTargetSpecLegacyTDF(cfg.tdfSpecVersion)) {
515
497
  aggregateHash = aggregateHash422;
516
498
  const payloadSigStr = await getSignatureVersion422(
517
- cfg.keyForEncryption.unwrappedKeyBinary,
499
+ cfg.keyForEncryption.unwrappedKey,
518
500
  Binary.fromString(aggregateHash),
519
501
  cfg.integrityAlgorithm,
520
502
  cfg.cryptoService
@@ -526,9 +508,10 @@ export async function writeStream(cfg: EncryptConfiguration): Promise<DecoratedR
526
508
  aggregateHash = await concatenateUint8Array(segmentHashList);
527
509
 
528
510
  const payloadSig = await getSignature(
529
- new Uint8Array(cfg.keyForEncryption.unwrappedKeyBinary.asArrayBuffer()),
511
+ cfg.keyForEncryption.unwrappedKey,
530
512
  aggregateHash,
531
- cfg.integrityAlgorithm
513
+ cfg.integrityAlgorithm,
514
+ cfg.cryptoService
532
515
  );
533
516
 
534
517
  const rootSig = base64.encodeArrayBuffer(payloadSig);
@@ -550,7 +533,7 @@ export async function writeStream(cfg: EncryptConfiguration): Promise<DecoratedR
550
533
  const systemMetadataConfigBase = assertions.getSystemMetadataAssertionConfig();
551
534
  const signingKeyForSystemMetadata: AssertionKey = {
552
535
  alg: 'HS256', // Default algorithm, can be configured if needed
553
- key: new Uint8Array(cfg.keyForEncryption.unwrappedKeyBinary.asArrayBuffer()),
536
+ key: cfg.keyForEncryption.unwrappedKey,
554
537
  };
555
538
  signedAssertions.push(
556
539
  await assertions.CreateAssertion(
@@ -559,6 +542,7 @@ export async function writeStream(cfg: EncryptConfiguration): Promise<DecoratedR
559
542
  ...systemMetadataConfigBase, // Spread the properties from the base config
560
543
  signingKey: signingKeyForSystemMetadata, // Add the signing key
561
544
  },
545
+ cfg.cryptoService,
562
546
  cfg.tdfSpecVersion // Pass the TDF spec version
563
547
  )
564
548
  );
@@ -569,7 +553,7 @@ export async function writeStream(cfg: EncryptConfiguration): Promise<DecoratedR
569
553
  // Create assertion using the assertionConfig values
570
554
  const signingKey: AssertionKey = assertionConfig.signingKey ?? {
571
555
  alg: 'HS256',
572
- key: new Uint8Array(cfg.keyForEncryption.unwrappedKeyBinary.asArrayBuffer()),
556
+ key: cfg.keyForEncryption.unwrappedKey,
573
557
  };
574
558
  const assertion = await assertions.CreateAssertion(
575
559
  aggregateHash,
@@ -577,6 +561,7 @@ export async function writeStream(cfg: EncryptConfiguration): Promise<DecoratedR
577
561
  ...assertionConfig,
578
562
  signingKey,
579
563
  },
564
+ cfg.cryptoService,
580
565
  cfg.tdfSpecVersion
581
566
  );
582
567
 
@@ -656,13 +641,13 @@ export async function writeStream(cfg: EncryptConfiguration): Promise<DecoratedR
656
641
  // Don't pass in an IV here. The encrypt function will generate one for you, ensuring that each segment has a unique IV.
657
642
  const encryptedResult = await cfg.encryptionInformation.encrypt(
658
643
  Binary.fromArrayBuffer(chunk.buffer),
659
- cfg.keyForEncryption.unwrappedKeyBinary
644
+ cfg.keyForEncryption.unwrappedKey
660
645
  );
661
646
  const payloadBuffer = new Uint8Array(encryptedResult.payload.asByteArray());
662
647
  let hash: string;
663
648
  if (isTargetSpecLegacyTDF(cfg.tdfSpecVersion)) {
664
649
  const payloadSigStr = await getSignatureVersion422(
665
- cfg.keyForEncryption.unwrappedKeyBinary,
650
+ cfg.keyForEncryption.unwrappedKey,
666
651
  encryptedResult.payload,
667
652
  cfg.segmentIntegrityAlgorithm,
668
653
  cfg.cryptoService
@@ -672,9 +657,10 @@ export async function writeStream(cfg: EncryptConfiguration): Promise<DecoratedR
672
657
  hash = base64.encode(payloadSigStr);
673
658
  } else {
674
659
  const payloadSig = await getSignature(
675
- new Uint8Array(cfg.keyForEncryption.unwrappedKeyBinary.asArrayBuffer()),
660
+ cfg.keyForEncryption.unwrappedKey,
676
661
  new Uint8Array(encryptedResult.payload.asArrayBuffer()),
677
- cfg.segmentIntegrityAlgorithm
662
+ cfg.segmentIntegrityAlgorithm,
663
+ cfg.cryptoService
678
664
  );
679
665
 
680
666
  segmentHashList.push(new Uint8Array(payloadSig));
@@ -762,7 +748,7 @@ async function unwrapKey({
762
748
  allowedKases: OriginAllowList;
763
749
  authProvider: AuthProvider;
764
750
  concurrencyLimit?: number;
765
- dpopKeys: CryptoKeyPair;
751
+ dpopKeys: KeyPair;
766
752
  cryptoService: CryptoService;
767
753
  wrappingKeyAlgorithm?: KasPublicKeyAlgorithm;
768
754
  fulfillableObligations: string[];
@@ -777,19 +763,21 @@ async function unwrapKey({
777
763
 
778
764
  async function tryKasRewrap(keySplitInfo: KeyAccessObject): Promise<RewrapResponseData> {
779
765
  const url = `${keySplitInfo.url}/v2/rewrap`;
780
- let ephemeralEncryptionKeysRaw: AnyKeyPair;
781
- let ephemeralEncryptionKeys: PemKeyPair;
766
+ let ephemeralEncryptionKeys: KeyPair;
782
767
  if (wrappingKeyAlgorithm === 'ec:secp256r1') {
783
- ephemeralEncryptionKeysRaw = await generateKeyPair();
784
- ephemeralEncryptionKeys = await cryptoService.cryptoToPemPair(ephemeralEncryptionKeysRaw);
768
+ // Generate EC key pair via CryptoService (returns opaque keys)
769
+ ephemeralEncryptionKeys = await cryptoService.generateECKeyPair('P-256');
785
770
  } else if (wrappingKeyAlgorithm === 'rsa:2048' || !wrappingKeyAlgorithm) {
786
- ephemeralEncryptionKeysRaw = await cryptoService.generateKeyPair();
787
- ephemeralEncryptionKeys = await cryptoService.cryptoToPemPair(ephemeralEncryptionKeysRaw);
771
+ // generateKeyPair() returns opaque keys
772
+ ephemeralEncryptionKeys = await cryptoService.generateKeyPair();
788
773
  } else {
789
774
  throw new ConfigurationError(`Unsupported wrapping key algorithm [${wrappingKeyAlgorithm}]`);
790
775
  }
791
776
 
792
- const clientPublicKey = ephemeralEncryptionKeys.publicKey;
777
+ // Export public key to PEM for protobuf request
778
+ const clientPublicKey = await cryptoService.exportPublicKeyPem(
779
+ ephemeralEncryptionKeys.publicKey
780
+ );
793
781
 
794
782
  // Convert keySplitInfo to protobuf KeyAccess
795
783
  const keyAccessProto = create(KeyAccessSchema, {
@@ -836,7 +824,7 @@ async function unwrapKey({
836
824
  const requestBodyStr = toJsonString(UnsignedRewrapRequestSchema, unsignedRequest);
837
825
 
838
826
  const jwtPayload = { requestBody: requestBodyStr };
839
- const signedRequestToken = await reqSignature(jwtPayload, dpopKeys.privateKey);
827
+ const signedRequestToken = await reqSignature(jwtPayload, dpopKeys.privateKey, cryptoService);
840
828
 
841
829
  const rewrapResp = await fetchWrappedKey(
842
830
  url,
@@ -862,20 +850,35 @@ async function unwrapKey({
862
850
  const entityWrappedKey = result.result.value;
863
851
 
864
852
  if (wrappingKeyAlgorithm === 'ec:secp256r1') {
865
- const serverEphemeralKey: CryptoKey = await pemPublicToCrypto(sessionPublicKey);
866
- const ekr = ephemeralEncryptionKeysRaw as CryptoKeyPair;
867
- const kek = await keyAgreement(ekr.privateKey, serverEphemeralKey, {
868
- hkdfSalt: await ztdfSalt,
869
- hkdfHash: 'SHA-256',
853
+ // Import KAS session public key from PEM
854
+ const sessionPublicKeyOpaque = await cryptoService.importPublicKey(sessionPublicKey, {
855
+ usage: 'derive',
870
856
  });
857
+
858
+ // Derive decryption key using ECDH + HKDF via CryptoService (returns SymmetricKey)
859
+ const derivedKey = await cryptoService.deriveKeyFromECDH(
860
+ ephemeralEncryptionKeys.privateKey,
861
+ sessionPublicKeyOpaque,
862
+ {
863
+ hash: 'SHA-256',
864
+ salt: await getZtdfSalt(cryptoService),
865
+ }
866
+ );
867
+
871
868
  const wrappedKeyAndNonce = entityWrappedKey;
872
869
  const iv = wrappedKeyAndNonce.slice(0, 12);
873
870
  const wrappedKey = wrappedKeyAndNonce.slice(12);
874
871
 
875
- const dek = await crypto.subtle.decrypt({ name: 'AES-GCM', iv }, kek, wrappedKey);
872
+ // Decrypt using CryptoService with opaque symmetric key
873
+ const decryptResult = await cryptoService.decrypt(
874
+ Binary.fromArrayBuffer(wrappedKey.buffer),
875
+ derivedKey, // SymmetricKey (opaque)
876
+ Binary.fromArrayBuffer(iv.buffer),
877
+ Algorithms.AES_256_GCM
878
+ );
876
879
 
877
880
  return {
878
- key: new Uint8Array(dek),
881
+ key: new Uint8Array(decryptResult.payload.asArrayBuffer()),
879
882
  metadata,
880
883
  requiredObligations,
881
884
  };
@@ -937,14 +940,17 @@ async function unwrapKey({
937
940
  const splitKeys = [];
938
941
  const requiredObligations = new Set<string>();
939
942
  for (const resp of rewrapResponseData) {
940
- splitKeys.push(resp.key);
943
+ // Import each split key as opaque SymmetricKey
944
+ const splitKeyOpaque = await cryptoService.importSymmetricKey(resp.key);
945
+ splitKeys.push(splitKeyOpaque);
941
946
  for (const requiredObligation of resp.requiredObligations) {
942
947
  requiredObligations.add(requiredObligation.toLowerCase());
943
948
  }
944
949
  }
945
- const reconstructedKey = keyMerge(splitKeys);
950
+ // Merge symmetric keys via CryptoService
951
+ const reconstructedKey = await cryptoService.mergeSymmetricKeys(splitKeys);
946
952
  return {
947
- reconstructedKeyBinary: Binary.fromArrayBuffer(reconstructedKey),
953
+ reconstructedKey, // SymmetricKey (opaque)
948
954
  metadata: rewrapResponseData[0].metadata, // Use metadata from first split
949
955
  requiredObligations: [...requiredObligations],
950
956
  };
@@ -968,19 +974,21 @@ function handleRewrapError(error: Error) {
968
974
 
969
975
  async function decryptChunk(
970
976
  encryptedChunk: Uint8Array,
971
- reconstructedKeyBinary: Binary,
977
+ reconstructedKey: SymmetricKey,
972
978
  hash: string,
973
979
  cipher: SymmetricCipher,
974
980
  segmentIntegrityAlgorithm: IntegrityAlgorithm,
975
- specVersion: string
981
+ specVersion: string,
982
+ cryptoService: CryptoService
976
983
  ): Promise<DecryptResult> {
977
984
  if (segmentIntegrityAlgorithm !== 'GMAC' && segmentIntegrityAlgorithm !== 'HS256') {
978
985
  throw new UnsupportedError(`Unsupported integrity alg [${segmentIntegrityAlgorithm}]`);
979
986
  }
980
987
  const segmentSig = await getSignature(
981
- new Uint8Array(reconstructedKeyBinary.asArrayBuffer()),
988
+ reconstructedKey, // SymmetricKey (opaque)
982
989
  encryptedChunk,
983
- segmentIntegrityAlgorithm
990
+ segmentIntegrityAlgorithm,
991
+ cryptoService
984
992
  );
985
993
 
986
994
  const segmentHash = isTargetSpecLegacyTDF(specVersion)
@@ -990,14 +998,14 @@ async function decryptChunk(
990
998
  if (hash !== segmentHash) {
991
999
  throw new IntegrityError('Failed integrity check on segment hash');
992
1000
  }
993
- return await cipher.decrypt(encryptedChunk, reconstructedKeyBinary);
1001
+ return await cipher.decrypt(encryptedChunk, reconstructedKey);
994
1002
  }
995
1003
 
996
1004
  async function updateChunkQueue(
997
1005
  chunkMap: Chunk[],
998
1006
  centralDirectory: CentralDirectory[],
999
1007
  zipReader: ZipReader,
1000
- reconstructedKeyBinary: Binary,
1008
+ reconstructedKey: SymmetricKey,
1001
1009
  cipher: SymmetricCipher,
1002
1010
  segmentIntegrityAlgorithm: IntegrityAlgorithm,
1003
1011
  cryptoService: CryptoService,
@@ -1038,7 +1046,7 @@ async function updateChunkQueue(
1038
1046
  sliceAndDecrypt({
1039
1047
  buffer,
1040
1048
  cryptoService,
1041
- reconstructedKeyBinary,
1049
+ reconstructedKey,
1042
1050
  slice,
1043
1051
  cipher,
1044
1052
  segmentIntegrityAlgorithm,
@@ -1052,14 +1060,15 @@ async function updateChunkQueue(
1052
1060
 
1053
1061
  export async function sliceAndDecrypt({
1054
1062
  buffer,
1055
- reconstructedKeyBinary,
1063
+ reconstructedKey,
1056
1064
  slice,
1057
1065
  cipher,
1066
+ cryptoService,
1058
1067
  segmentIntegrityAlgorithm,
1059
1068
  specVersion,
1060
1069
  }: {
1061
1070
  buffer: Uint8Array;
1062
- reconstructedKeyBinary: Binary;
1071
+ reconstructedKey: SymmetricKey;
1063
1072
  slice: Chunk[];
1064
1073
  cipher: SymmetricCipher;
1065
1074
  cryptoService: CryptoService;
@@ -1082,11 +1091,12 @@ export async function sliceAndDecrypt({
1082
1091
  try {
1083
1092
  const result = await decryptChunk(
1084
1093
  encryptedChunk,
1085
- reconstructedKeyBinary,
1094
+ reconstructedKey,
1086
1095
  slice[index]['hash'],
1087
1096
  cipher,
1088
1097
  segmentIntegrityAlgorithm,
1089
- specVersion
1098
+ specVersion,
1099
+ cryptoService
1090
1100
  );
1091
1101
  if (plainSegmentSize && result.payload.length() !== plainSegmentSize) {
1092
1102
  throw new DecryptError(
@@ -1130,7 +1140,7 @@ export async function decryptStreamFrom(
1130
1140
  segmentSizeDefault,
1131
1141
  segments,
1132
1142
  } = manifest.encryptionInformation.integrityInformation;
1133
- const { metadata, reconstructedKeyBinary, requiredObligations } = await unwrapKey({
1143
+ const { metadata, reconstructedKey, requiredObligations } = await unwrapKey({
1134
1144
  fulfillableObligations: cfg.fulfillableObligations,
1135
1145
  manifest,
1136
1146
  authProvider: cfg.authProvider,
@@ -1139,7 +1149,7 @@ export async function decryptStreamFrom(
1139
1149
  cryptoService: cfg.cryptoService,
1140
1150
  });
1141
1151
  // async function unwrapKey(manifest: Manifest, allowedKases: string[], authProvider: AuthProvider | AppIdAuthProvider, publicKey: string, privateKey: string, entity: EntityObject) {
1142
- const keyForDecryption = await cfg.keyMiddleware(reconstructedKeyBinary);
1152
+ const keyForDecryption = await cfg.keyMiddleware(reconstructedKey);
1143
1153
  const encryptedSegmentSizeDefault = defaultSegmentSize || DEFAULT_SEGMENT_SIZE;
1144
1154
 
1145
1155
  // check if the TDF is a legacy TDF
@@ -1160,9 +1170,10 @@ export async function decryptStreamFrom(
1160
1170
  }
1161
1171
 
1162
1172
  const payloadSig = await getSignature(
1163
- new Uint8Array(keyForDecryption.asArrayBuffer()),
1173
+ keyForDecryption, // SymmetricKey (opaque)
1164
1174
  aggregateHash,
1165
- integrityAlgorithm
1175
+ integrityAlgorithm,
1176
+ cfg.cryptoService
1166
1177
  );
1167
1178
 
1168
1179
  if (!cfg.noVerifyAssertions) {
@@ -1170,7 +1181,7 @@ export async function decryptStreamFrom(
1170
1181
  // Create a default assertion key
1171
1182
  let assertionKey: AssertionKey = {
1172
1183
  alg: 'HS256',
1173
- key: new Uint8Array(reconstructedKeyBinary.asArrayBuffer()),
1184
+ key: keyForDecryption, // SymmetricKey (opaque)
1174
1185
  };
1175
1186
 
1176
1187
  if (cfg.assertionVerificationKeys) {
@@ -1179,7 +1190,13 @@ export async function decryptStreamFrom(
1179
1190
  assertionKey = foundKey;
1180
1191
  }
1181
1192
  }
1182
- await assertions.verify(assertion, aggregateHash, assertionKey, isLegacyTDF);
1193
+ await assertions.verify(
1194
+ assertion,
1195
+ aggregateHash,
1196
+ assertionKey,
1197
+ isLegacyTDF,
1198
+ cfg.cryptoService
1199
+ );
1183
1200
  }
1184
1201
  }
1185
1202
 
@@ -1,8 +1,7 @@
1
- import * as WebCryptoService from '../crypto/index.js';
2
1
  import { KeyInfo, SplitKey } from '../models/index.js';
3
-
4
2
  import { AesGcmCipher } from '../ciphers/aes-gcm-cipher.js';
5
3
  import { ConfigurationError } from '../../../src/errors.js';
4
+ import { type CryptoService } from '../crypto/declarations.js';
6
5
  import { decodeArrayBuffer, encodeArrayBuffer } from '../../../src/encodings/base64.js';
7
6
 
8
7
  export { ZipReader, readUInt64LE } from './zip-reader.js';
@@ -292,15 +291,15 @@ export function base64ToBytes(str: string): Uint8Array {
292
291
  *
293
292
  * @returns {Object}:
294
293
  * {
295
- * keyForEncryption: Binary;
296
- * keyForManifest: Binary;
294
+ * keyForEncryption: KeyInfo;
295
+ * keyForManifest: KeyInfo;
297
296
  * }
298
297
  */
299
- export async function keyMiddleware(): Promise<{
298
+ export async function keyMiddleware(cryptoService: CryptoService): Promise<{
300
299
  keyForEncryption: KeyInfo;
301
300
  keyForManifest: KeyInfo;
302
301
  }> {
303
- const cipher = new AesGcmCipher(WebCryptoService);
302
+ const cipher = new AesGcmCipher(cryptoService);
304
303
  const encryptionInformation = new SplitKey(cipher);
305
304
  if (!encryptionInformation?.generateKey) {
306
305
  throw new ConfigurationError('Crypto service not initialised');