@opentdf/sdk 0.2.0-beta.1758 → 0.2.0

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 (265) hide show
  1. package/README.md +45 -38
  2. package/dist/cjs/src/access.js +47 -11
  3. package/dist/cjs/src/auth/auth.js +5 -5
  4. package/dist/cjs/src/auth/oidc-clientcredentials-provider.js +1 -1
  5. package/dist/cjs/src/auth/oidc-externaljwt-provider.js +1 -1
  6. package/dist/cjs/src/auth/oidc-refreshtoken-provider.js +1 -1
  7. package/dist/cjs/src/auth/oidc.js +1 -1
  8. package/dist/cjs/src/auth/providers.js +1 -1
  9. package/dist/cjs/src/concurrency.js +3 -4
  10. package/dist/cjs/src/encodings/base64.js +4 -4
  11. package/dist/cjs/src/encodings/hex.js +5 -6
  12. package/dist/cjs/src/encodings/index.js +18 -8
  13. package/dist/cjs/src/errors.js +1 -1
  14. package/dist/cjs/src/index.js +28 -318
  15. package/dist/cjs/src/nanoclients.js +285 -0
  16. package/dist/cjs/src/nanoindex.js +47 -0
  17. package/dist/cjs/src/nanotdf/Client.js +18 -8
  18. package/dist/cjs/src/nanotdf/NanoTDF.js +1 -1
  19. package/dist/cjs/src/nanotdf/decrypt.js +2 -2
  20. package/dist/cjs/src/nanotdf/encrypt-dataset.js +2 -2
  21. package/dist/cjs/src/nanotdf/encrypt.js +2 -2
  22. package/dist/cjs/src/nanotdf/helpers/calculateByCurve.js +3 -4
  23. package/dist/cjs/src/nanotdf/helpers/getHkdfSalt.js +2 -2
  24. package/dist/cjs/src/nanotdf/models/Ciphers.js +3 -3
  25. package/dist/cjs/src/nanotdf/models/EcCurves.js +3 -3
  26. package/dist/cjs/src/nanotdf/models/Header.js +1 -1
  27. package/dist/cjs/src/nanotdf/models/Payload.js +1 -1
  28. package/dist/cjs/src/nanotdf/models/Policy/AbstractPolicy.js +1 -1
  29. package/dist/cjs/src/nanotdf/models/Policy/EmbeddedPolicy.js +1 -1
  30. package/dist/cjs/src/nanotdf/models/Policy/PolicyFactory.js +1 -1
  31. package/dist/cjs/src/nanotdf/models/ResourceLocator.js +1 -1
  32. package/dist/cjs/src/nanotdf/models/Signature.js +1 -1
  33. package/dist/cjs/src/nanotdf-crypto/ciphers.js +1 -1
  34. package/dist/cjs/src/nanotdf-crypto/decrypt.js +2 -2
  35. package/dist/cjs/src/nanotdf-crypto/digest.js +2 -2
  36. package/dist/cjs/src/nanotdf-crypto/ecdsaSignature.js +4 -5
  37. package/dist/cjs/src/nanotdf-crypto/encrypt.js +2 -2
  38. package/dist/cjs/src/nanotdf-crypto/exportCryptoKey.js +2 -2
  39. package/dist/cjs/src/nanotdf-crypto/generateKeyPair.js +2 -2
  40. package/dist/cjs/src/nanotdf-crypto/generateRandomNumber.js +2 -2
  41. package/dist/cjs/src/nanotdf-crypto/index.js +21 -13
  42. package/dist/cjs/src/nanotdf-crypto/keyAgreement.js +10 -8
  43. package/dist/cjs/src/nanotdf-crypto/pemPublicToCrypto.js +20 -11
  44. package/dist/cjs/src/opentdf.js +251 -0
  45. package/dist/cjs/src/policy/api.js +2 -3
  46. package/dist/cjs/src/policy/granter.js +3 -4
  47. package/dist/cjs/src/seekable.js +157 -0
  48. package/dist/cjs/src/tdf/AttributeObject.js +2 -4
  49. package/dist/cjs/src/tdf/Policy.js +1 -2
  50. package/dist/cjs/src/utils.js +12 -14
  51. package/dist/cjs/src/version.js +6 -2
  52. package/dist/cjs/tdf3/index.js +27 -15
  53. package/dist/cjs/tdf3/src/assertions.js +25 -11
  54. package/dist/cjs/tdf3/src/binary.js +1 -1
  55. package/dist/cjs/tdf3/src/ciphers/aes-gcm-cipher.js +1 -1
  56. package/dist/cjs/tdf3/src/ciphers/symmetric-cipher-base.js +1 -1
  57. package/dist/cjs/tdf3/src/client/DecoratedReadableStream.js +7 -74
  58. package/dist/cjs/tdf3/src/client/builders.js +26 -22
  59. package/dist/cjs/tdf3/src/client/index.js +88 -61
  60. package/dist/cjs/tdf3/src/client/validation.js +3 -3
  61. package/dist/cjs/tdf3/src/crypto/crypto-utils.js +1 -1
  62. package/dist/cjs/tdf3/src/crypto/index.js +18 -18
  63. package/dist/cjs/tdf3/src/index.js +22 -11
  64. package/dist/cjs/tdf3/src/models/attribute-set.js +1 -1
  65. package/dist/cjs/tdf3/src/models/encryption-information.js +3 -3
  66. package/dist/cjs/tdf3/src/models/key-access.js +67 -35
  67. package/dist/cjs/tdf3/src/models/policy.js +3 -3
  68. package/dist/cjs/tdf3/src/tdf.js +177 -151
  69. package/dist/cjs/tdf3/src/utils/buffer-crc32.js +2 -3
  70. package/dist/cjs/tdf3/src/utils/index.js +30 -28
  71. package/dist/cjs/tdf3/src/utils/keysplit.js +4 -5
  72. package/dist/cjs/tdf3/src/utils/unwrap.js +21 -0
  73. package/dist/cjs/tdf3/src/utils/zip-reader.js +4 -4
  74. package/dist/cjs/tdf3/src/utils/zip-writer.js +4 -4
  75. package/dist/types/src/access.d.ts +3 -0
  76. package/dist/types/src/access.d.ts.map +1 -1
  77. package/dist/types/src/auth/providers.d.ts.map +1 -1
  78. package/dist/types/src/index.d.ts +5 -136
  79. package/dist/types/src/index.d.ts.map +1 -1
  80. package/dist/types/src/nanoclients.d.ts +107 -0
  81. package/dist/types/src/nanoclients.d.ts.map +1 -0
  82. package/dist/types/src/nanoindex.d.ts +5 -0
  83. package/dist/types/src/nanoindex.d.ts.map +1 -0
  84. package/dist/types/src/nanotdf/enum/CipherEnum.d.ts +1 -1
  85. package/dist/types/src/nanotdf/enum/CipherEnum.d.ts.map +1 -1
  86. package/dist/types/src/nanotdf/enum/PolicyTypeEnum.d.ts +1 -1
  87. package/dist/types/src/nanotdf/enum/PolicyTypeEnum.d.ts.map +1 -1
  88. package/dist/types/src/nanotdf/models/DefaultParams.d.ts +1 -1
  89. package/dist/types/src/nanotdf/models/ResourceLocator.d.ts.map +1 -1
  90. package/dist/types/src/nanotdf-crypto/generateKeyPair.d.ts +1 -1
  91. package/dist/types/src/nanotdf-crypto/generateKeyPair.d.ts.map +1 -1
  92. package/dist/types/src/nanotdf-crypto/generateRandomNumber.d.ts +1 -1
  93. package/dist/types/src/nanotdf-crypto/generateRandomNumber.d.ts.map +1 -1
  94. package/dist/types/src/nanotdf-crypto/index.d.ts +2 -3
  95. package/dist/types/src/nanotdf-crypto/index.d.ts.map +1 -1
  96. package/dist/types/src/nanotdf-crypto/keyAgreement.d.ts.map +1 -1
  97. package/dist/types/src/opentdf.d.ts +110 -0
  98. package/dist/types/src/opentdf.d.ts.map +1 -0
  99. package/dist/types/src/seekable.d.ts +39 -0
  100. package/dist/types/src/seekable.d.ts.map +1 -0
  101. package/dist/types/src/tdf/AttributeObject.d.ts +0 -2
  102. package/dist/types/src/tdf/AttributeObject.d.ts.map +1 -1
  103. package/dist/types/src/tdf/NanoTDF/NanoTDF.d.ts +2 -2
  104. package/dist/types/src/tdf/NanoTDF/NanoTDF.d.ts.map +1 -1
  105. package/dist/types/src/tdf/Policy.d.ts.map +1 -1
  106. package/dist/types/src/tdf/PolicyObject.d.ts +0 -1
  107. package/dist/types/src/tdf/PolicyObject.d.ts.map +1 -1
  108. package/dist/types/src/utils.d.ts +0 -1
  109. package/dist/types/src/utils.d.ts.map +1 -1
  110. package/dist/types/src/version.d.ts +4 -0
  111. package/dist/types/src/version.d.ts.map +1 -1
  112. package/dist/types/tdf3/index.d.ts +3 -2
  113. package/dist/types/tdf3/index.d.ts.map +1 -1
  114. package/dist/types/tdf3/src/assertions.d.ts +3 -3
  115. package/dist/types/tdf3/src/assertions.d.ts.map +1 -1
  116. package/dist/types/tdf3/src/client/DecoratedReadableStream.d.ts +1 -13
  117. package/dist/types/tdf3/src/client/DecoratedReadableStream.d.ts.map +1 -1
  118. package/dist/types/tdf3/src/client/builders.d.ts +43 -37
  119. package/dist/types/tdf3/src/client/builders.d.ts.map +1 -1
  120. package/dist/types/tdf3/src/client/index.d.ts +8 -9
  121. package/dist/types/tdf3/src/client/index.d.ts.map +1 -1
  122. package/dist/types/tdf3/src/client/validation.d.ts +3 -3
  123. package/dist/types/tdf3/src/client/validation.d.ts.map +1 -1
  124. package/dist/types/tdf3/src/crypto/crypto-utils.d.ts.map +1 -1
  125. package/dist/types/tdf3/src/index.d.ts +1 -1
  126. package/dist/types/tdf3/src/index.d.ts.map +1 -1
  127. package/dist/types/tdf3/src/models/key-access.d.ts +63 -15
  128. package/dist/types/tdf3/src/models/key-access.d.ts.map +1 -1
  129. package/dist/types/tdf3/src/models/manifest.d.ts +2 -0
  130. package/dist/types/tdf3/src/models/manifest.d.ts.map +1 -1
  131. package/dist/types/tdf3/src/models/policy.d.ts +0 -1
  132. package/dist/types/tdf3/src/models/policy.d.ts.map +1 -1
  133. package/dist/types/tdf3/src/tdf.d.ts +20 -24
  134. package/dist/types/tdf3/src/tdf.d.ts.map +1 -1
  135. package/dist/types/tdf3/src/utils/index.d.ts +0 -2
  136. package/dist/types/tdf3/src/utils/index.d.ts.map +1 -1
  137. package/dist/types/tdf3/src/utils/unwrap.d.ts +2 -0
  138. package/dist/types/tdf3/src/utils/unwrap.d.ts.map +1 -0
  139. package/dist/types/tdf3/src/utils/zip-reader.d.ts +1 -1
  140. package/dist/types/tdf3/src/utils/zip-reader.d.ts.map +1 -1
  141. package/dist/types/tdf3/src/utils/zip-writer.d.ts +2 -2
  142. package/dist/web/src/access.js +40 -7
  143. package/dist/web/src/auth/auth.js +1 -1
  144. package/dist/web/src/auth/oidc-clientcredentials-provider.js +1 -1
  145. package/dist/web/src/auth/oidc-externaljwt-provider.js +1 -1
  146. package/dist/web/src/auth/oidc-refreshtoken-provider.js +1 -1
  147. package/dist/web/src/auth/oidc.js +1 -1
  148. package/dist/web/src/auth/providers.js +1 -1
  149. package/dist/web/src/concurrency.js +1 -1
  150. package/dist/web/src/encodings/base64.js +1 -1
  151. package/dist/web/src/encodings/hex.js +1 -1
  152. package/dist/web/src/errors.js +1 -1
  153. package/dist/web/src/index.js +6 -310
  154. package/dist/web/src/nanoclients.js +280 -0
  155. package/dist/web/src/nanoindex.js +5 -0
  156. package/dist/web/src/nanotdf/Client.js +1 -1
  157. package/dist/web/src/nanotdf/NanoTDF.js +1 -1
  158. package/dist/web/src/nanotdf/encrypt-dataset.js +1 -1
  159. package/dist/web/src/nanotdf/encrypt.js +1 -1
  160. package/dist/web/src/nanotdf/models/Ciphers.js +1 -1
  161. package/dist/web/src/nanotdf/models/EcCurves.js +1 -1
  162. package/dist/web/src/nanotdf/models/Header.js +1 -1
  163. package/dist/web/src/nanotdf/models/Payload.js +1 -1
  164. package/dist/web/src/nanotdf/models/Policy/AbstractPolicy.js +1 -1
  165. package/dist/web/src/nanotdf/models/Policy/EmbeddedPolicy.js +1 -1
  166. package/dist/web/src/nanotdf/models/Policy/PolicyFactory.js +1 -1
  167. package/dist/web/src/nanotdf/models/ResourceLocator.js +1 -1
  168. package/dist/web/src/nanotdf/models/Signature.js +1 -1
  169. package/dist/web/src/nanotdf-crypto/ciphers.js +1 -1
  170. package/dist/web/src/nanotdf-crypto/ecdsaSignature.js +1 -1
  171. package/dist/web/src/nanotdf-crypto/generateKeyPair.js +2 -2
  172. package/dist/web/src/nanotdf-crypto/generateRandomNumber.js +2 -2
  173. package/dist/web/src/nanotdf-crypto/index.js +3 -4
  174. package/dist/web/src/nanotdf-crypto/keyAgreement.js +9 -6
  175. package/dist/web/src/nanotdf-crypto/pemPublicToCrypto.js +1 -1
  176. package/dist/web/src/opentdf.js +242 -0
  177. package/dist/web/src/policy/api.js +1 -1
  178. package/dist/web/src/policy/granter.js +1 -1
  179. package/dist/web/src/seekable.js +148 -0
  180. package/dist/web/src/tdf/AttributeObject.js +1 -2
  181. package/dist/web/src/tdf/Policy.js +1 -2
  182. package/dist/web/src/utils.js +2 -3
  183. package/dist/web/src/version.js +5 -1
  184. package/dist/web/tdf3/index.js +3 -2
  185. package/dist/web/tdf3/src/assertions.js +21 -6
  186. package/dist/web/tdf3/src/binary.js +1 -1
  187. package/dist/web/tdf3/src/ciphers/aes-gcm-cipher.js +1 -1
  188. package/dist/web/tdf3/src/ciphers/symmetric-cipher-base.js +1 -1
  189. package/dist/web/tdf3/src/client/DecoratedReadableStream.js +4 -68
  190. package/dist/web/tdf3/src/client/builders.js +26 -22
  191. package/dist/web/tdf3/src/client/index.js +69 -52
  192. package/dist/web/tdf3/src/client/validation.js +1 -1
  193. package/dist/web/tdf3/src/crypto/crypto-utils.js +1 -1
  194. package/dist/web/tdf3/src/crypto/index.js +1 -1
  195. package/dist/web/tdf3/src/index.js +2 -2
  196. package/dist/web/tdf3/src/models/attribute-set.js +1 -1
  197. package/dist/web/tdf3/src/models/encryption-information.js +3 -3
  198. package/dist/web/tdf3/src/models/key-access.js +47 -24
  199. package/dist/web/tdf3/src/models/policy.js +1 -1
  200. package/dist/web/tdf3/src/tdf.js +149 -130
  201. package/dist/web/tdf3/src/utils/buffer-crc32.js +1 -1
  202. package/dist/web/tdf3/src/utils/index.js +1 -5
  203. package/dist/web/tdf3/src/utils/keysplit.js +1 -1
  204. package/dist/web/tdf3/src/utils/unwrap.js +18 -0
  205. package/dist/web/tdf3/src/utils/zip-reader.js +1 -1
  206. package/dist/web/tdf3/src/utils/zip-writer.js +1 -1
  207. package/package.json +45 -42
  208. package/src/access.ts +37 -1
  209. package/src/index.ts +5 -435
  210. package/src/nanoclients.ts +405 -0
  211. package/src/nanoindex.ts +4 -0
  212. package/src/nanotdf-crypto/generateKeyPair.ts +1 -1
  213. package/src/nanotdf-crypto/generateRandomNumber.ts +1 -1
  214. package/src/nanotdf-crypto/index.ts +2 -3
  215. package/src/nanotdf-crypto/keyAgreement.ts +14 -7
  216. package/src/opentdf.ts +473 -0
  217. package/{tdf3/src/utils/chunkers.ts → src/seekable.ts} +69 -20
  218. package/src/tdf/AttributeObject.ts +0 -3
  219. package/src/tdf/Policy.ts +0 -1
  220. package/src/tdf/PolicyObject.ts +0 -1
  221. package/src/utils.ts +1 -3
  222. package/src/version.ts +5 -0
  223. package/tdf3/index.ts +14 -2
  224. package/tdf3/src/assertions.ts +33 -8
  225. package/tdf3/src/client/DecoratedReadableStream.ts +2 -78
  226. package/tdf3/src/client/builders.ts +44 -26
  227. package/tdf3/src/client/index.ts +101 -86
  228. package/tdf3/src/index.ts +1 -1
  229. package/tdf3/src/models/encryption-information.ts +2 -2
  230. package/tdf3/src/models/key-access.ts +120 -38
  231. package/tdf3/src/models/manifest.ts +3 -0
  232. package/tdf3/src/models/policy.ts +0 -1
  233. package/tdf3/src/tdf.ts +251 -207
  234. package/tdf3/src/utils/index.ts +0 -5
  235. package/tdf3/src/utils/unwrap.ts +17 -0
  236. package/tdf3/src/utils/zip-reader.ts +1 -1
  237. package/dist/cjs/src/nanotdf-crypto/importRawKey.js +0 -18
  238. package/dist/cjs/tdf3/src/templates/default.html.js +0 -98
  239. package/dist/cjs/tdf3/src/templates/escaper.js +0 -15
  240. package/dist/cjs/tdf3/src/templates/index.js +0 -12
  241. package/dist/cjs/tdf3/src/utils/chunkers.js +0 -114
  242. package/dist/cjs/tdf3/src/version.js +0 -6
  243. package/dist/types/src/nanotdf-crypto/importRawKey.d.ts +0 -13
  244. package/dist/types/src/nanotdf-crypto/importRawKey.d.ts.map +0 -1
  245. package/dist/types/tdf3/src/templates/default.html.d.ts +0 -8
  246. package/dist/types/tdf3/src/templates/default.html.d.ts.map +0 -1
  247. package/dist/types/tdf3/src/templates/escaper.d.ts +0 -6
  248. package/dist/types/tdf3/src/templates/escaper.d.ts.map +0 -1
  249. package/dist/types/tdf3/src/templates/index.d.ts +0 -3
  250. package/dist/types/tdf3/src/templates/index.d.ts.map +0 -1
  251. package/dist/types/tdf3/src/utils/chunkers.d.ts +0 -29
  252. package/dist/types/tdf3/src/utils/chunkers.d.ts.map +0 -1
  253. package/dist/types/tdf3/src/version.d.ts +0 -3
  254. package/dist/types/tdf3/src/version.d.ts.map +0 -1
  255. package/dist/web/src/nanotdf-crypto/importRawKey.js +0 -15
  256. package/dist/web/tdf3/src/templates/default.html.js +0 -96
  257. package/dist/web/tdf3/src/templates/escaper.js +0 -10
  258. package/dist/web/tdf3/src/templates/index.js +0 -3
  259. package/dist/web/tdf3/src/utils/chunkers.js +0 -107
  260. package/dist/web/tdf3/src/version.js +0 -3
  261. package/src/nanotdf-crypto/importRawKey.ts +0 -19
  262. package/tdf3/src/templates/default.html.ts +0 -105
  263. package/tdf3/src/templates/escaper.ts +0 -10
  264. package/tdf3/src/templates/index.ts +0 -2
  265. package/tdf3/src/version.ts +0 -2
package/tdf3/src/tdf.ts CHANGED
@@ -1,35 +1,16 @@
1
- import { unsigned } from './utils/buffer-crc32.js';
2
1
  import { exportSPKI, importX509 } from 'jose';
3
- import { DecoratedReadableStream } from './client/DecoratedReadableStream.js';
4
- import { fetchKasPubKey as fetchKasPubKeyV2, fetchWrappedKey } from '../../src/access.js';
5
- import { DecryptParams } from './client/builders.js';
6
- import { AssertionConfig, AssertionKey, AssertionVerificationKeys } from './assertions.js';
7
- import * as assertions from './assertions.js';
8
2
 
9
3
  import {
10
- KeyAccessType,
11
- KeyInfo,
12
- Manifest,
13
- Policy,
14
- Remote as KeyAccessRemote,
15
- SplitKey,
16
- Wrapped as KeyAccessWrapped,
17
- KeyAccess,
18
- KeyAccessObject,
19
- SplitType,
20
- } from './models/index.js';
21
- import { base64 } from '../../src/encodings/index.js';
22
- import {
23
- type Chunker,
24
- ZipReader,
25
- ZipWriter,
26
- base64ToBuffer,
27
- keyMerge,
28
- buffToString,
29
- concatUint8,
30
- } from './utils/index.js';
31
- import { Binary } from './binary.js';
32
- import { KasPublicKeyAlgorithm, KasPublicKeyInfo, OriginAllowList } from '../../src/access.js';
4
+ KasPublicKeyAlgorithm,
5
+ KasPublicKeyInfo,
6
+ OriginAllowList,
7
+ fetchKasPubKey as fetchKasPubKeyV2,
8
+ fetchWrappedKey,
9
+ publicKeyAlgorithmToJwa,
10
+ } from '../../src/access.js';
11
+ import { type AuthProvider, reqSignature } from '../../src/auth/auth.js';
12
+ import { allPool, anyPool } from '../../src/concurrency.js';
13
+ import { base64, hex } from '../../src/encodings/index.js';
33
14
  import {
34
15
  ConfigurationError,
35
16
  DecryptError,
@@ -39,17 +20,40 @@ import {
39
20
  UnsafeUrlError,
40
21
  UnsupportedFeatureError as UnsupportedError,
41
22
  } from '../../src/errors.js';
42
- import { htmlWrapperTemplate } from './templates/index.js';
43
-
44
- // configurable
45
- // TODO: remove dependencies from ciphers so that we can open-source instead of relying on other Virtru libs
46
- import { AesGcmCipher } from './ciphers/index.js';
47
- import { type AuthProvider, reqSignature } from '../../src/auth/auth.js';
23
+ import { generateKeyPair } from '../../src/nanotdf-crypto/generateKeyPair.js';
24
+ import { keyAgreement } from '../../src/nanotdf-crypto/keyAgreement.js';
25
+ import { pemPublicToCrypto } from '../../src/nanotdf-crypto/pemPublicToCrypto.js';
26
+ import { type Chunker } from '../../src/seekable.js';
48
27
  import { PolicyObject } from '../../src/tdf/PolicyObject.js';
49
- import { type CryptoService, type DecryptResult } from './crypto/declarations.js';
50
- import { CentralDirectory } from './utils/zip-reader.js';
28
+ import { tdfSpecVersion } from '../../src/version.js';
29
+ import { AssertionConfig, AssertionKey, AssertionVerificationKeys } from './assertions.js';
30
+ import * as assertions from './assertions.js';
31
+ import { Binary } from './binary.js';
32
+ import { AesGcmCipher } from './ciphers/aes-gcm-cipher.js';
51
33
  import { SymmetricCipher } from './ciphers/symmetric-cipher-base.js';
52
- import { allPool, anyPool } from '../../src/concurrency.js';
34
+ import { DecryptParams } from './client/builders.js';
35
+ import { DecoratedReadableStream } from './client/DecoratedReadableStream.js';
36
+ import {
37
+ AnyKeyPair,
38
+ PemKeyPair,
39
+ type CryptoService,
40
+ type DecryptResult,
41
+ } from './crypto/declarations.js';
42
+ import {
43
+ ECWrapped,
44
+ KeyAccessType,
45
+ KeyInfo,
46
+ Manifest,
47
+ Policy,
48
+ SplitKey,
49
+ Wrapped,
50
+ KeyAccess,
51
+ KeyAccessObject,
52
+ SplitType,
53
+ } from './models/index.js';
54
+ import { unsigned } from './utils/buffer-crc32.js';
55
+ import { ZipReader, ZipWriter, keyMerge, concatUint8 } from './utils/index.js';
56
+ import { CentralDirectory } from './utils/zip-reader.js';
53
57
 
54
58
  // TODO: input validation on manifest JSON
55
59
  const DEFAULT_SEGMENT_SIZE = 1024 * 1024;
@@ -77,6 +81,7 @@ export type Metadata = {
77
81
 
78
82
  export type BuildKeyAccess = {
79
83
  type: KeyAccessType;
84
+ alg?: KasPublicKeyAlgorithm;
80
85
  url?: string;
81
86
  kid?: string;
82
87
  publicKey: string;
@@ -86,8 +91,8 @@ export type BuildKeyAccess = {
86
91
 
87
92
  type Segment = {
88
93
  hash: string;
89
- segmentSize: number | undefined;
90
- encryptedSegmentSize: number | undefined;
94
+ segmentSize?: number;
95
+ encryptedSegmentSize?: number;
91
96
  };
92
97
 
93
98
  type EntryInfo = {
@@ -97,20 +102,37 @@ type EntryInfo = {
97
102
  fileByteCount?: number;
98
103
  };
99
104
 
105
+ type Mailbox<T> = Promise<T> & {
106
+ set: (value: T) => void;
107
+ reject: (error: Error) => void;
108
+ };
109
+
110
+ function mailbox<T>(): Mailbox<T> {
111
+ let set: (value: T) => void;
112
+ let reject: (error: Error) => void;
113
+
114
+ const promise = new Promise<T>((resolve, rejectFn) => {
115
+ set = resolve;
116
+ reject = rejectFn;
117
+ }) as Mailbox<T>;
118
+
119
+ promise.set = set!;
120
+ promise.reject = reject!;
121
+
122
+ return promise;
123
+ }
124
+
100
125
  type Chunk = {
101
126
  hash: string;
127
+ plainSegmentSize?: number;
102
128
  encryptedOffset: number;
103
129
  encryptedSegmentSize?: number;
104
- decryptedChunk?: null | DecryptResult;
105
- promise: Promise<unknown>;
106
- _resolve?: (value: unknown) => void;
107
- _reject?: (value: unknown) => void;
130
+ decryptedChunk: Mailbox<DecryptResult>;
108
131
  };
109
132
 
110
133
  export type IntegrityAlgorithm = 'GMAC' | 'HS256';
111
134
 
112
135
  export type EncryptConfiguration = {
113
- allowedKases?: string[];
114
136
  allowList?: OriginAllowList;
115
137
  cryptoService: CryptoService;
116
138
  dpopKeys: CryptoKeyPair;
@@ -144,6 +166,7 @@ export type DecryptConfiguration = {
144
166
  assertionVerificationKeys?: AssertionVerificationKeys;
145
167
  noVerifyAssertions?: boolean;
146
168
  concurrencyLimit?: number;
169
+ wrappingKeyAlgorithm?: KasPublicKeyAlgorithm;
147
170
  };
148
171
 
149
172
  export type UpsertConfiguration = {
@@ -180,58 +203,17 @@ export async function fetchKasPublicKey(
180
203
  return fetchKasPubKeyV2(kas, algorithm || 'rsa:2048');
181
204
  }
182
205
 
183
- /**
184
- *
185
- * @param payload The TDF content to encode in HTML
186
- * @param manifest A copy of the manifest
187
- * @param transferUrl reader web-service start page
188
- * @return utf-8 encoded HTML data
189
- */
190
- export function wrapHtml(
191
- payload: Uint8Array,
192
- manifest: Manifest | string,
193
- transferUrl: string
194
- ): Uint8Array {
195
- const { origin } = new URL(transferUrl);
196
- const exportManifest: string = typeof manifest === 'string' ? manifest : JSON.stringify(manifest);
197
-
198
- const fullHtmlString = htmlWrapperTemplate({
199
- transferUrl,
200
- transferBaseUrl: origin,
201
- manifest: base64.encode(exportManifest),
202
- payload: buffToString(payload, 'base64'),
203
- });
204
-
205
- return new TextEncoder().encode(fullHtmlString);
206
- }
207
-
208
- export function unwrapHtml(htmlPayload: ArrayBuffer | Uint8Array | Binary | string) {
209
- let html;
210
- if (htmlPayload instanceof ArrayBuffer || ArrayBuffer.isView(htmlPayload)) {
211
- html = new TextDecoder().decode(htmlPayload);
212
- } else {
213
- html = htmlPayload.toString();
214
- }
215
- const payloadRe = /<input id=['"]?data-input['"]?[^>]*?value=['"]?([a-zA-Z0-9+/=]+)['"]?/;
216
- const reResult = payloadRe.exec(html);
217
- if (reResult === null) {
218
- throw new InvalidFileError('Payload is missing');
219
- }
220
- const base64Payload = reResult[1];
221
- try {
222
- return base64ToBuffer(base64Payload);
223
- } catch (e) {
224
- throw new InvalidFileError('There was a problem extracting the TDF3 payload', e);
225
- }
226
- }
227
-
228
- export async function extractPemFromKeyString(keyString: string): Promise<string> {
206
+ export async function extractPemFromKeyString(
207
+ keyString: string,
208
+ alg: KasPublicKeyAlgorithm
209
+ ): Promise<string> {
229
210
  let pem: string = keyString;
230
211
 
231
212
  // Skip the public key extraction if we find that the KAS url provides a
232
213
  // PEM-encoded key instead of certificate
233
214
  if (keyString.includes('CERTIFICATE')) {
234
- const cert = await importX509(keyString, 'RS256', { extractable: true });
215
+ const a = publicKeyAlgorithmToJwa(alg);
216
+ const cert = await importX509(keyString, a, { extractable: true });
235
217
  pem = await exportSPKI(cert);
236
218
  }
237
219
 
@@ -258,32 +240,34 @@ export async function buildKeyAccess({
258
240
  kid,
259
241
  metadata,
260
242
  sid = '',
243
+ alg = 'rsa:2048',
261
244
  }: BuildKeyAccess): Promise<KeyAccess> {
262
- /** Internal function to keep it DRY */
263
- function createKeyAccess(
264
- type: KeyAccessType,
265
- kasUrl: string,
266
- kasKeyIdentifier: string | undefined,
267
- pubKey: string,
268
- metadata?: Metadata
269
- ) {
270
- switch (type) {
271
- case 'wrapped':
272
- return new KeyAccessWrapped(kasUrl, kasKeyIdentifier, pubKey, metadata, sid);
273
- case 'remote':
274
- return new KeyAccessRemote(kasUrl, kasKeyIdentifier, pubKey, metadata, sid);
275
- default:
276
- throw new ConfigurationError(`buildKeyAccess: Key access type ${type} is unknown`);
277
- }
278
- }
279
-
280
245
  // if url and pulicKey are specified load the key access object with them
281
- if (url && publicKey) {
282
- return createKeyAccess(type, url, kid, await extractPemFromKeyString(publicKey), metadata);
246
+ if (!url && !publicKey) {
247
+ throw new ConfigurationError('TDF.buildKeyAccess: No source for kasUrl or pubKey');
248
+ } else if (!url) {
249
+ throw new ConfigurationError('TDF.buildKeyAccess: No kasUrl');
250
+ } else if (!publicKey) {
251
+ throw new ConfigurationError('TDF.buildKeyAccess: No kas public key');
283
252
  }
284
253
 
285
- // All failed. Raise an error.
286
- throw new ConfigurationError('TDF.buildKeyAccess: No source for kasUrl or pubKey');
254
+ let pubKey: string;
255
+ try {
256
+ pubKey = await extractPemFromKeyString(publicKey, alg);
257
+ } catch (e) {
258
+ throw new ConfigurationError(
259
+ `TDF.buildKeyAccess: Invalid public key [${publicKey}], caused by [${e}]`,
260
+ e
261
+ );
262
+ }
263
+ switch (type) {
264
+ case 'wrapped':
265
+ return new Wrapped(url, kid, pubKey, metadata, sid);
266
+ case 'ec-wrapped':
267
+ return new ECWrapped(url, kid, pubKey, metadata, sid);
268
+ default:
269
+ throw new ConfigurationError(`buildKeyAccess: Key access type [${type}] is unsupported`);
270
+ }
287
271
  }
288
272
 
289
273
  export function validatePolicyObject(policy: Policy): void {
@@ -312,7 +296,6 @@ async function _generateManifest(
312
296
  url: '0.payload',
313
297
  protocol: 'zip',
314
298
  isEncrypted: true,
315
- schemaVersion: '3.0.0',
316
299
  ...(mimeType && { mimeType }),
317
300
  };
318
301
 
@@ -323,25 +306,34 @@ async function _generateManifest(
323
306
  // generate the manifest first, then insert integrity information into it
324
307
  encryptionInformation: encryptionInformationStr,
325
308
  assertions: assertions,
309
+ schemaVersion: tdfSpecVersion,
326
310
  };
327
311
  }
328
312
 
329
313
  async function getSignature(
330
- unwrappedKeyBinary: Binary,
331
- payloadBinary: Binary,
332
- algorithmType: IntegrityAlgorithm,
333
- cryptoService: CryptoService
334
- ) {
314
+ unwrappedKey: Uint8Array,
315
+ content: Uint8Array,
316
+ algorithmType: IntegrityAlgorithm
317
+ ): Promise<Uint8Array> {
335
318
  switch (algorithmType.toUpperCase()) {
336
319
  case 'GMAC':
337
320
  // use the auth tag baked into the encrypted payload
338
- return buffToString(Uint8Array.from(payloadBinary.asByteArray()).slice(-16), 'hex');
339
- case 'HS256':
321
+ return content.slice(-16);
322
+ case 'HS256': {
340
323
  // simple hmac is the default
341
- return await cryptoService.hmac(
342
- buffToString(new Uint8Array(unwrappedKeyBinary.asArrayBuffer()), 'hex'),
343
- buffToString(new Uint8Array(payloadBinary.asArrayBuffer()), 'utf-8')
324
+ const cryptoKey = await crypto.subtle.importKey(
325
+ 'raw',
326
+ unwrappedKey,
327
+ {
328
+ name: 'HMAC',
329
+ hash: { name: 'SHA-256' },
330
+ },
331
+ true,
332
+ ['sign', 'verify']
344
333
  );
334
+ const signature = await crypto.subtle.sign('HMAC', cryptoKey, content);
335
+ return new Uint8Array(signature);
336
+ }
345
337
  default:
346
338
  throw new ConfigurationError(`Unsupported signature alg [${algorithmType}]`);
347
339
  }
@@ -375,7 +367,7 @@ export async function writeStream(cfg: EncryptConfiguration): Promise<DecoratedR
375
367
  let bytesProcessed = 0;
376
368
  let crcCounter = 0;
377
369
  let fileByteCount = 0;
378
- let aggregateHash = '';
370
+ const segmentHashList: Uint8Array[] = [];
379
371
 
380
372
  const zipWriter = new ZipWriter();
381
373
  const manifest = await _generateManifest(
@@ -468,14 +460,16 @@ export async function writeStream(cfg: EncryptConfiguration): Promise<DecoratedR
468
460
  fileByteCount = 0;
469
461
 
470
462
  // hash the concat of all hashes
471
- const payloadSigStr = await getSignature(
472
- cfg.keyForEncryption.unwrappedKeyBinary,
473
- Binary.fromString(aggregateHash),
474
- cfg.integrityAlgorithm,
475
- cfg.cryptoService
463
+ const aggregateHash = await concatenateUint8Array(segmentHashList);
464
+
465
+ const payloadSig = await getSignature(
466
+ new Uint8Array(cfg.keyForEncryption.unwrappedKeyBinary.asArrayBuffer()),
467
+ aggregateHash,
468
+ cfg.integrityAlgorithm
476
469
  );
477
- manifest.encryptionInformation.integrityInformation.rootSignature.sig =
478
- base64.encode(payloadSigStr);
470
+
471
+ const rootSig = base64.encodeArrayBuffer(payloadSig);
472
+ manifest.encryptionInformation.integrityInformation.rootSignature.sig = rootSig;
479
473
  manifest.encryptionInformation.integrityInformation.rootSignature.alg =
480
474
  cfg.integrityAlgorithm;
481
475
 
@@ -581,18 +575,16 @@ export async function writeStream(cfg: EncryptConfiguration): Promise<DecoratedR
581
575
  cfg.keyForEncryption.unwrappedKeyBinary
582
576
  );
583
577
  const payloadBuffer = new Uint8Array(encryptedResult.payload.asByteArray());
584
- const payloadSigStr = await getSignature(
585
- cfg.keyForEncryption.unwrappedKeyBinary,
586
- encryptedResult.payload,
587
- cfg.segmentIntegrityAlgorithm,
588
- cfg.cryptoService
578
+ const payloadSig = await getSignature(
579
+ new Uint8Array(cfg.keyForEncryption.unwrappedKeyBinary.asArrayBuffer()),
580
+ new Uint8Array(encryptedResult.payload.asArrayBuffer()),
581
+ cfg.segmentIntegrityAlgorithm
589
582
  );
590
583
 
591
- // combined string of all hashes for root signature
592
- aggregateHash += payloadSigStr;
584
+ segmentHashList.push(new Uint8Array(payloadSig));
593
585
 
594
586
  segmentInfos.push({
595
- hash: base64.encode(payloadSigStr),
587
+ hash: base64.encodeArrayBuffer(payloadSig),
596
588
  segmentSize: chunk.length === segmentSizeDefault ? undefined : chunk.length,
597
589
  encryptedSegmentSize:
598
590
  payloadBuffer.length === encryptedSegmentSizeDefault ? undefined : payloadBuffer.length,
@@ -660,6 +652,7 @@ async function unwrapKey({
660
652
  dpopKeys,
661
653
  concurrencyLimit,
662
654
  cryptoService,
655
+ wrappingKeyAlgorithm,
663
656
  }: {
664
657
  manifest: Manifest;
665
658
  allowedKases: OriginAllowList;
@@ -667,6 +660,7 @@ async function unwrapKey({
667
660
  concurrencyLimit?: number;
668
661
  dpopKeys: CryptoKeyPair;
669
662
  cryptoService: CryptoService;
663
+ wrappingKeyAlgorithm?: KasPublicKeyAlgorithm;
670
664
  }) {
671
665
  if (authProvider === undefined) {
672
666
  throw new ConfigurationError(
@@ -678,9 +672,18 @@ async function unwrapKey({
678
672
 
679
673
  async function tryKasRewrap(keySplitInfo: KeyAccessObject): Promise<RewrapResponseData> {
680
674
  const url = `${keySplitInfo.url}/v2/rewrap`;
681
- const ephemeralEncryptionKeys = await cryptoService.cryptoToPemPair(
682
- await cryptoService.generateKeyPair()
683
- );
675
+ let ephemeralEncryptionKeysRaw: AnyKeyPair;
676
+ let ephemeralEncryptionKeys: PemKeyPair;
677
+ if (wrappingKeyAlgorithm === 'ec:secp256r1') {
678
+ ephemeralEncryptionKeysRaw = await generateKeyPair();
679
+ ephemeralEncryptionKeys = await cryptoService.cryptoToPemPair(ephemeralEncryptionKeysRaw);
680
+ } else if (wrappingKeyAlgorithm === 'rsa:2048' || !wrappingKeyAlgorithm) {
681
+ ephemeralEncryptionKeysRaw = await cryptoService.generateKeyPair();
682
+ ephemeralEncryptionKeys = await cryptoService.cryptoToPemPair(ephemeralEncryptionKeysRaw);
683
+ } else {
684
+ throw new ConfigurationError(`Unsupported wrapping key algorithm [${wrappingKeyAlgorithm}]`);
685
+ }
686
+
684
687
  const clientPublicKey = ephemeralEncryptionKeys.publicKey;
685
688
 
686
689
  const requestBodyStr = JSON.stringify({
@@ -693,13 +696,31 @@ async function unwrapKey({
693
696
  const jwtPayload = { requestBody: requestBodyStr };
694
697
  const signedRequestToken = await reqSignature(jwtPayload, dpopKeys.privateKey);
695
698
 
696
- const { entityWrappedKey, metadata } = await fetchWrappedKey(
699
+ const { entityWrappedKey, metadata, sessionPublicKey } = await fetchWrappedKey(
697
700
  url,
698
701
  { signedRequestToken },
699
702
  authProvider,
700
703
  '0.0.1'
701
704
  );
702
705
 
706
+ if (wrappingKeyAlgorithm === 'ec:secp256r1') {
707
+ const serverEphemeralKey: CryptoKey = await pemPublicToCrypto(sessionPublicKey);
708
+ const ekr = ephemeralEncryptionKeysRaw as CryptoKeyPair;
709
+ const kek = await keyAgreement(ekr.privateKey, serverEphemeralKey, {
710
+ hkdfSalt: new TextEncoder().encode('salt'),
711
+ hkdfHash: 'SHA-256',
712
+ });
713
+ const wrappedKeyAndNonce = base64.decodeArrayBuffer(entityWrappedKey);
714
+ const iv = wrappedKeyAndNonce.slice(0, 12);
715
+ const wrappedKey = wrappedKeyAndNonce.slice(12);
716
+
717
+ const dek = await crypto.subtle.decrypt({ name: 'AES-GCM', iv }, kek, wrappedKey);
718
+
719
+ return {
720
+ key: new Uint8Array(dek),
721
+ metadata,
722
+ };
723
+ }
703
724
  const key = Binary.fromString(base64.decode(entityWrappedKey));
704
725
  const decryptedKeyBinary = await cryptoService.decryptWithPrivateKey(
705
726
  key,
@@ -769,17 +790,22 @@ async function decryptChunk(
769
790
  hash: string,
770
791
  cipher: SymmetricCipher,
771
792
  segmentIntegrityAlgorithm: IntegrityAlgorithm,
772
- cryptoService: CryptoService
793
+ isLegacyTDF: boolean
773
794
  ): Promise<DecryptResult> {
774
795
  if (segmentIntegrityAlgorithm !== 'GMAC' && segmentIntegrityAlgorithm !== 'HS256') {
796
+ throw new UnsupportedError(`Unsupported integrity alg [${segmentIntegrityAlgorithm}]`);
775
797
  }
776
- const segmentHashStr = await getSignature(
777
- reconstructedKeyBinary,
778
- Binary.fromArrayBuffer(encryptedChunk.buffer),
779
- segmentIntegrityAlgorithm,
780
- cryptoService
798
+ const segmentSig = await getSignature(
799
+ new Uint8Array(reconstructedKeyBinary.asArrayBuffer()),
800
+ encryptedChunk,
801
+ segmentIntegrityAlgorithm
781
802
  );
782
- if (hash !== btoa(segmentHashStr)) {
803
+
804
+ const segmentHash = isLegacyTDF
805
+ ? base64.encode(hex.encodeArrayBuffer(segmentSig))
806
+ : base64.encodeArrayBuffer(segmentSig);
807
+
808
+ if (hash !== segmentHash) {
783
809
  throw new IntegrityError('Failed integrity check on segment hash');
784
810
  }
785
811
  return await cipher.decrypt(encryptedChunk, reconstructedKeyBinary);
@@ -792,7 +818,8 @@ async function updateChunkQueue(
792
818
  reconstructedKeyBinary: Binary,
793
819
  cipher: SymmetricCipher,
794
820
  segmentIntegrityAlgorithm: IntegrityAlgorithm,
795
- cryptoService: CryptoService
821
+ cryptoService: CryptoService,
822
+ isLegacyTDF: boolean
796
823
  ) {
797
824
  const chunksInOneDownload = 500;
798
825
  let requests = [];
@@ -833,6 +860,7 @@ async function updateChunkQueue(
833
860
  slice,
834
861
  cipher,
835
862
  segmentIntegrityAlgorithm,
863
+ isLegacyTDF,
836
864
  });
837
865
  }
838
866
  })()
@@ -845,8 +873,8 @@ export async function sliceAndDecrypt({
845
873
  reconstructedKeyBinary,
846
874
  slice,
847
875
  cipher,
848
- cryptoService,
849
876
  segmentIntegrityAlgorithm,
877
+ isLegacyTDF,
850
878
  }: {
851
879
  buffer: Uint8Array;
852
880
  reconstructedKeyBinary: Binary;
@@ -854,9 +882,10 @@ export async function sliceAndDecrypt({
854
882
  cipher: SymmetricCipher;
855
883
  cryptoService: CryptoService;
856
884
  segmentIntegrityAlgorithm: IntegrityAlgorithm;
885
+ isLegacyTDF: boolean;
857
886
  }) {
858
887
  for (const index in slice) {
859
- const { encryptedOffset, encryptedSegmentSize, _resolve, _reject } = slice[index];
888
+ const { encryptedOffset, encryptedSegmentSize, plainSegmentSize } = slice[index];
860
889
 
861
890
  const offset =
862
891
  slice[0].encryptedOffset === 0 ? encryptedOffset : encryptedOffset % slice[0].encryptedOffset;
@@ -864,6 +893,10 @@ export async function sliceAndDecrypt({
864
893
  buffer.slice(offset, offset + (encryptedSegmentSize as number))
865
894
  );
866
895
 
896
+ if (encryptedChunk.length !== encryptedSegmentSize) {
897
+ throw new DecryptError('Failed to fetch entire segment');
898
+ }
899
+
867
900
  try {
868
901
  const result = await decryptChunk(
869
902
  encryptedChunk,
@@ -871,18 +904,16 @@ export async function sliceAndDecrypt({
871
904
  slice[index]['hash'],
872
905
  cipher,
873
906
  segmentIntegrityAlgorithm,
874
- cryptoService
907
+ isLegacyTDF
875
908
  );
876
- slice[index].decryptedChunk = result;
877
- if (_resolve) {
878
- _resolve(null);
909
+ if (plainSegmentSize && result.payload.length() !== plainSegmentSize) {
910
+ throw new DecryptError(
911
+ `incorrect segment size: found [${result.payload.length()}], expected [${plainSegmentSize}]`
912
+ );
879
913
  }
914
+ slice[index].decryptedChunk.set(result);
880
915
  } catch (e) {
881
- if (_reject) {
882
- _reject(e);
883
- } else {
884
- throw e;
885
- }
916
+ slice[index].decryptedChunk.reject(e);
886
917
  }
887
918
  }
888
919
  }
@@ -905,6 +936,7 @@ export async function readStream(cfg: DecryptConfiguration) {
905
936
  encryptedSegmentSizeDefault: defaultSegmentSize,
906
937
  rootSignature,
907
938
  segmentHashAlg,
939
+ segmentSizeDefault,
908
940
  segments,
909
941
  } = manifest.encryptionInformation.integrityInformation;
910
942
  const { metadata, reconstructedKeyBinary } = await unwrapKey({
@@ -918,25 +950,28 @@ export async function readStream(cfg: DecryptConfiguration) {
918
950
  const keyForDecryption = await cfg.keyMiddleware(reconstructedKeyBinary);
919
951
  const encryptedSegmentSizeDefault = defaultSegmentSize || DEFAULT_SEGMENT_SIZE;
920
952
 
921
- // check the combined string of hashes
922
- const aggregateHash = segments.map(({ hash }) => base64.decode(hash)).join('');
953
+ // check if the TDF is a legacy TDF
954
+ const specVersion = manifest.schemaVersion || manifest.tdf_spec_version;
955
+ const isLegacyTDF = !specVersion || specVersion.startsWith('3.');
956
+
957
+ // Decode each hash and store it in an array of Uint8Array
958
+ const segmentHashList = segments.map(
959
+ ({ hash }) => new Uint8Array(base64.decodeArrayBuffer(hash))
960
+ );
961
+
962
+ // Concatenate all segment hashes into a single Uint8Array
963
+ const aggregateHash = await concatenateUint8Array(segmentHashList);
964
+
923
965
  const integrityAlgorithm = rootSignature.alg;
924
966
  if (integrityAlgorithm !== 'GMAC' && integrityAlgorithm !== 'HS256') {
925
967
  throw new UnsupportedError(`Unsupported integrity alg [${integrityAlgorithm}]`);
926
968
  }
927
- const payloadSigStr = await getSignature(
928
- keyForDecryption,
929
- Binary.fromString(aggregateHash),
930
- integrityAlgorithm,
931
- cfg.cryptoService
932
- );
933
969
 
934
- if (
935
- manifest.encryptionInformation.integrityInformation.rootSignature.sig !==
936
- base64.encode(payloadSigStr)
937
- ) {
938
- throw new IntegrityError('Failed integrity check on root signature');
939
- }
970
+ const payloadSig = await getSignature(
971
+ new Uint8Array(keyForDecryption.asArrayBuffer()),
972
+ aggregateHash,
973
+ integrityAlgorithm
974
+ );
940
975
 
941
976
  if (!cfg.noVerifyAssertions) {
942
977
  for (const assertion of manifest.assertions || []) {
@@ -952,31 +987,40 @@ export async function readStream(cfg: DecryptConfiguration) {
952
987
  assertionKey = foundKey;
953
988
  }
954
989
  }
955
- await assertions.verify(assertion, aggregateHash, assertionKey);
990
+ await assertions.verify(assertion, aggregateHash, assertionKey, isLegacyTDF);
956
991
  }
957
992
  }
958
993
 
994
+ const rootSig = isLegacyTDF
995
+ ? base64.encode(hex.encodeArrayBuffer(payloadSig))
996
+ : base64.encodeArrayBuffer(payloadSig);
997
+
998
+ if (manifest.encryptionInformation.integrityInformation.rootSignature.sig !== rootSig) {
999
+ throw new IntegrityError('Failed integrity check on root signature');
1000
+ }
1001
+
959
1002
  let mapOfRequestsOffset = 0;
960
1003
  const chunkMap = new Map(
961
- segments.map(({ hash, encryptedSegmentSize = encryptedSegmentSizeDefault }) => {
962
- const result = (() => {
963
- let _resolve, _reject;
964
- const chunk: Chunk = {
965
- hash,
966
- encryptedOffset: mapOfRequestsOffset,
967
- encryptedSegmentSize,
968
- promise: new Promise((resolve, reject) => {
969
- _resolve = resolve;
970
- _reject = reject;
971
- }),
972
- };
973
- chunk._resolve = _resolve;
974
- chunk._reject = _reject;
975
- return chunk;
976
- })();
977
- mapOfRequestsOffset += encryptedSegmentSize || encryptedSegmentSizeDefault;
978
- return [hash, result];
979
- })
1004
+ segments.map(
1005
+ ({
1006
+ hash,
1007
+ encryptedSegmentSize = encryptedSegmentSizeDefault,
1008
+ segmentSize = segmentSizeDefault,
1009
+ }) => {
1010
+ const result = (() => {
1011
+ const chunk: Chunk = {
1012
+ hash,
1013
+ encryptedOffset: mapOfRequestsOffset,
1014
+ encryptedSegmentSize,
1015
+ decryptedChunk: mailbox<DecryptResult>(),
1016
+ plainSegmentSize: segmentSize,
1017
+ };
1018
+ return chunk;
1019
+ })();
1020
+ mapOfRequestsOffset += encryptedSegmentSize;
1021
+ return [hash, result];
1022
+ }
1023
+ )
980
1024
  );
981
1025
 
982
1026
  const cipher = new AesGcmCipher(cfg.cryptoService);
@@ -993,7 +1037,8 @@ export async function readStream(cfg: DecryptConfiguration) {
993
1037
  keyForDecryption,
994
1038
  cipher,
995
1039
  segmentIntegrityAlg,
996
- cfg.cryptoService
1040
+ cfg.cryptoService,
1041
+ isLegacyTDF
997
1042
  );
998
1043
 
999
1044
  let progress = 0;
@@ -1005,16 +1050,11 @@ export async function readStream(cfg: DecryptConfiguration) {
1005
1050
  }
1006
1051
 
1007
1052
  const [hash, chunk] = chunkMap.entries().next().value;
1008
- if (!chunk.decryptedChunk) {
1009
- await chunk.promise;
1010
- }
1011
- const decryptedSegment = chunk.decryptedChunk;
1053
+ const decryptedSegment = await chunk.decryptedChunk;
1012
1054
 
1013
1055
  controller.enqueue(new Uint8Array(decryptedSegment.payload.asByteArray()));
1014
1056
  progress += chunk.encryptedSegmentSize;
1015
1057
  cfg.progressHandler?.(progress);
1016
-
1017
- chunk.decryptedChunk = null;
1018
1058
  chunkMap.delete(hash);
1019
1059
  },
1020
1060
  ...(cfg.fileStreamServiceWorker && { fileStreamServiceWorker: cfg.fileStreamServiceWorker }),
@@ -1023,8 +1063,12 @@ export async function readStream(cfg: DecryptConfiguration) {
1023
1063
  const outputStream = new DecoratedReadableStream(underlyingSource);
1024
1064
 
1025
1065
  outputStream.manifest = manifest;
1026
- outputStream.emit('manifest', manifest);
1027
1066
  outputStream.metadata = metadata;
1028
- outputStream.emit('rewrap', metadata);
1029
1067
  return outputStream;
1030
1068
  }
1069
+
1070
+ async function concatenateUint8Array(uint8arrays: Uint8Array[]): Promise<Uint8Array> {
1071
+ const blob = new Blob(uint8arrays);
1072
+ const buffer = await blob.arrayBuffer();
1073
+ return new Uint8Array(buffer);
1074
+ }