@opentdf/sdk 0.2.0-beta.1758 → 0.2.0-beta.1941

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 +243 -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 +106 -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 +234 -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 +441 -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
@@ -1,24 +1,20 @@
1
1
  import { v4 } from 'uuid';
2
2
  import {
3
3
  ZipReader,
4
- fromBuffer,
5
- fromDataSource,
6
4
  streamToBuffer,
7
- type Chunker,
8
5
  keyMiddleware as defaultKeyMiddleware,
9
6
  } from '../utils/index.js';
10
7
  import { base64 } from '../../../src/encodings/index.js';
11
8
  import {
12
9
  buildKeyAccess,
13
- EncryptConfiguration,
10
+ type EncryptConfiguration,
14
11
  fetchKasPublicKey,
15
12
  loadTDFStream,
16
- unwrapHtml,
17
13
  validatePolicyObject,
18
14
  readStream,
19
- wrapHtml,
20
15
  writeStream,
21
16
  } from '../tdf.js';
17
+ import { unwrapHtml } from '../utils/unwrap.js';
22
18
  import { OIDCRefreshTokenProvider } from '../../../src/auth/oidc-refreshtoken-provider.js';
23
19
  import { OIDCExternalJwtProvider } from '../../../src/auth/oidc-externaljwt-provider.js';
24
20
  import { CryptoService } from '../crypto/declarations.js';
@@ -26,13 +22,13 @@ import { type AuthProvider, HttpRequest, withHeaders } from '../../../src/auth/a
26
22
  import { pemToCryptoPublicKey, rstrip, validateSecureUrl } from '../../../src/utils.js';
27
23
 
28
24
  import {
29
- EncryptParams,
30
- DecryptParams,
25
+ type EncryptParams,
26
+ type DecryptParams,
31
27
  type Scope,
32
- DecryptStreamMiddleware,
33
- EncryptKeyMiddleware,
34
- EncryptStreamMiddleware,
35
- SplitStep,
28
+ type DecryptStreamMiddleware,
29
+ type EncryptKeyMiddleware,
30
+ type EncryptStreamMiddleware,
31
+ type SplitStep,
36
32
  } from './builders.js';
37
33
  import { DecoratedReadableStream } from './DecoratedReadableStream.js';
38
34
 
@@ -42,25 +38,51 @@ import {
42
38
  type DecryptSource,
43
39
  EncryptParamsBuilder,
44
40
  } from './builders.js';
45
- import { KasPublicKeyInfo, OriginAllowList } from '../../../src/access.js';
41
+ import {
42
+ type KasPublicKeyInfo,
43
+ keyAlgorithmToPublicKeyAlgorithm,
44
+ OriginAllowList,
45
+ } from '../../../src/access.js';
46
46
  import { ConfigurationError } from '../../../src/errors.js';
47
47
  import { Binary } from '../binary.js';
48
48
  import { AesGcmCipher } from '../ciphers/aes-gcm-cipher.js';
49
49
  import { toCryptoKeyPair } from '../crypto/crypto-utils.js';
50
50
  import * as defaultCryptoService from '../crypto/index.js';
51
- import { type AttributeObject, type Policy, SplitKey } from '../models/index.js';
51
+ import {
52
+ type AttributeObject,
53
+ type KeyAccessType,
54
+ type Policy,
55
+ SplitKey,
56
+ } from '../models/index.js';
52
57
  import { plan } from '../../../src/policy/granter.js';
53
58
  import { attributeFQNsAsValues } from '../../../src/policy/api.js';
54
59
  import { type Value } from '../../../src/policy/attributes.js';
60
+ import { type Chunker, fromBuffer, fromSource } from '../../../src/seekable.js';
55
61
 
56
62
  const GLOBAL_BYTE_LIMIT = 64 * 1000 * 1000 * 1000; // 64 GB, see WS-9363.
57
- const HTML_BYTE_LIMIT = 100 * 1000 * 1000; // 100 MB, see WS-9476.
58
63
 
59
64
  // No default config for now. Delegate to Virtru wrapper for endpoints.
60
65
  const defaultClientConfig = { oidcOrigin: '', cryptoService: defaultCryptoService };
61
66
 
62
67
  const getFirstTwoBytes = async (chunker: Chunker) => new TextDecoder().decode(await chunker(0, 2));
63
68
 
69
+ // Convert a PEM string to a CryptoKey
70
+ export const resolveKasInfo = async (
71
+ pem: string,
72
+ uri: string,
73
+ kid?: string
74
+ ): Promise<KasPublicKeyInfo> => {
75
+ const k: CryptoKey = await pemToCryptoPublicKey(pem);
76
+ const algorithm = keyAlgorithmToPublicKeyAlgorithm(k.algorithm);
77
+ return {
78
+ key: Promise.resolve(k),
79
+ publicKey: pem,
80
+ url: uri,
81
+ algorithm,
82
+ kid: kid,
83
+ };
84
+ };
85
+
64
86
  const makeChunkable = async (source: DecryptSource) => {
65
87
  if (!source) {
66
88
  throw new ConfigurationError('invalid source');
@@ -82,7 +104,7 @@ const makeChunkable = async (source: DecryptSource) => {
82
104
  initialChunker = source.location;
83
105
  break;
84
106
  default:
85
- initialChunker = await fromDataSource(source);
107
+ initialChunker = await fromSource(source);
86
108
  }
87
109
 
88
110
  const magic: string = await getFirstTwoBytes(initialChunker);
@@ -99,7 +121,7 @@ const makeChunkable = async (source: DecryptSource) => {
99
121
 
100
122
  export interface ClientConfig {
101
123
  cryptoService?: CryptoService;
102
- organizationName?: string;
124
+ /// oauth client id; used to generate oauth authProvider
103
125
  clientId?: string;
104
126
  dpopEnabled?: boolean;
105
127
  dpopKeys?: Promise<CryptoKeyPair>;
@@ -217,7 +239,7 @@ export class Client {
217
239
  */
218
240
  readonly allowedKases: OriginAllowList;
219
241
 
220
- readonly kasKeys: Record<string, Promise<KasPublicKeyInfo>> = {};
242
+ readonly kasKeys: Record<string, Promise<KasPublicKeyInfo>[]> = {};
221
243
 
222
244
  readonly easEndpoint?: string;
223
245
 
@@ -323,12 +345,9 @@ export class Client {
323
345
  dpopKeys: clientConfig.dpopKeys,
324
346
  });
325
347
  if (clientConfig.kasPublicKey) {
326
- this.kasKeys[this.kasEndpoint] = Promise.resolve({
327
- url: this.kasEndpoint,
328
- algorithm: 'rsa:2048',
329
- key: pemToCryptoPublicKey(clientConfig.kasPublicKey),
330
- publicKey: clientConfig.kasPublicKey,
331
- });
348
+ this.kasKeys[this.kasEndpoint] = [
349
+ resolveKasInfo(clientConfig.kasPublicKey, this.kasEndpoint),
350
+ ];
332
351
  }
333
352
  }
334
353
 
@@ -337,7 +356,6 @@ export class Client {
337
356
  *
338
357
  * @param scope dissem and attributes for constructing the policy
339
358
  * @param source source object of unencrypted data
340
- * @param [asHtml] If we should wrap the TDF data in a self-opening HTML wrapper. Defaults to false
341
359
  * @param [autoconfigure] If we should use scope.attributes to configure KAOs
342
360
  * @param [metadata] Additional non-secret data to store with the TDF
343
361
  * @param [opts] Test only
@@ -348,28 +366,29 @@ export class Client {
348
366
  * @param [eo] - (deprecated) entity object
349
367
  * @return a {@link https://nodejs.org/api/stream.html#stream_class_stream_readable|Readable} a new stream containing the TDF ciphertext
350
368
  */
351
- async encrypt({
352
- scope = { attributes: [], dissem: [] },
353
- autoconfigure,
354
- source,
355
- asHtml = false,
356
- metadata,
357
- mimeType,
358
- offline = true,
359
- windowSize = DEFAULT_SEGMENT_SIZE,
360
- keyMiddleware = defaultKeyMiddleware,
361
- streamMiddleware = async (stream: DecoratedReadableStream) => stream,
362
- splitPlan,
363
- assertionConfigs = [],
364
- }: EncryptParams): Promise<DecoratedReadableStream> {
365
- if (!offline) {
369
+ async encrypt(opts: EncryptParams): Promise<DecoratedReadableStream> {
370
+ if (opts.offline === false) {
366
371
  throw new ConfigurationError('online mode not supported');
367
372
  }
373
+ if (opts.asHtml) {
374
+ throw new ConfigurationError('html mode not supported');
375
+ }
368
376
  const dpopKeys = await this.dpopKeys;
377
+ const {
378
+ autoconfigure,
379
+ metadata,
380
+ mimeType = 'unknown',
381
+ windowSize = DEFAULT_SEGMENT_SIZE,
382
+ keyMiddleware = defaultKeyMiddleware,
383
+ streamMiddleware = async (stream: DecoratedReadableStream) => stream,
384
+ wrappingKeyAlgorithm = 'rsa:2048',
385
+ } = opts;
386
+ const scope = opts.scope ?? { attributes: [], dissem: [] };
369
387
 
370
388
  const policyObject = asPolicy(scope);
371
389
  validatePolicyObject(policyObject);
372
390
 
391
+ let splitPlan = opts.splitPlan;
373
392
  if (!splitPlan && autoconfigure) {
374
393
  let avs: Value[] = scope.attributeValues ?? [];
375
394
  const fqns: string[] = scope.attributes
@@ -395,7 +414,7 @@ export class Client {
395
414
  }
396
415
  }
397
416
  if (
398
- avs.length != scope.attributes?.length ||
417
+ avs.length != (scope.attributes?.length || 0) ||
399
418
  !avs.map(({ fqn }) => fqn).every((a) => fqns.indexOf(a) >= 0)
400
419
  ) {
401
420
  throw new ConfigurationError(
@@ -408,18 +427,9 @@ export class Client {
408
427
  splitPlan = detailedPlan.map((kat) => {
409
428
  const { kas, sid } = kat;
410
429
  if (kas?.publicKey?.cached?.keys && !(kas.uri in this.kasKeys)) {
411
- const keys = kas.publicKey.cached.keys.filter(
412
- ({ alg }) => alg == 'KAS_PUBLIC_KEY_ALG_ENUM_RSA_2048'
413
- );
430
+ const keys = kas.publicKey.cached.keys;
414
431
  if (keys?.length) {
415
- const key = keys[0];
416
- this.kasKeys[kas.uri] = Promise.resolve({
417
- key: pemToCryptoPublicKey(key.pem),
418
- publicKey: key.pem,
419
- url: kas.uri,
420
- algorithm: 'rsa:2048',
421
- kid: key.kid,
422
- });
432
+ this.kasKeys[kas.uri] = keys.map((key) => resolveKasInfo(key.pem, kas.uri, key.kid));
423
433
  }
424
434
  }
425
435
  return { kas: kas.uri, sid };
@@ -428,17 +438,40 @@ export class Client {
428
438
 
429
439
  // TODO: Refactor underlying builder to remove some of this unnecessary config.
430
440
 
431
- const byteLimit = asHtml ? HTML_BYTE_LIMIT : GLOBAL_BYTE_LIMIT;
441
+ const maxByteLimit = GLOBAL_BYTE_LIMIT;
442
+ const byteLimit =
443
+ opts.byteLimit === undefined || opts.byteLimit <= 0 || opts.byteLimit > maxByteLimit
444
+ ? maxByteLimit
445
+ : opts.byteLimit;
432
446
  const encryptionInformation = new SplitKey(new AesGcmCipher(this.cryptoService));
433
- const splits: SplitStep[] = splitPlan?.length ? splitPlan : [{ kas: this.kasEndpoint }];
447
+ const splits: SplitStep[] = splitPlan?.length
448
+ ? splitPlan
449
+ : [{ kas: opts.defaultKASEndpoint ?? this.kasEndpoint }];
434
450
  encryptionInformation.keyAccess = await Promise.all(
435
451
  splits.map(async ({ kas, sid }) => {
436
452
  if (!(kas in this.kasKeys)) {
437
- this.kasKeys[kas] = fetchKasPublicKey(kas);
453
+ this.kasKeys[kas] = [fetchKasPublicKey(kas, wrappingKeyAlgorithm)];
454
+ }
455
+ const kasPublicKey = await Promise.any(this.kasKeys[kas]);
456
+ if (kasPublicKey.algorithm !== wrappingKeyAlgorithm) {
457
+ console.warn(
458
+ `Mismatched wrapping key algorithm: [${kasPublicKey.algorithm}] is not requested type, [${wrappingKeyAlgorithm}]`
459
+ );
460
+ }
461
+ let type: KeyAccessType;
462
+ switch (kasPublicKey.algorithm) {
463
+ case 'rsa:2048':
464
+ type = 'wrapped';
465
+ break;
466
+ case 'ec:secp256r1':
467
+ type = 'ec-wrapped';
468
+ break;
469
+ default:
470
+ throw new ConfigurationError(`Unsupported algorithm ${kasPublicKey.algorithm}`);
438
471
  }
439
- const kasPublicKey = await this.kasKeys[kas];
440
472
  return buildKeyAccess({
441
- type: offline ? 'wrapped' : 'remote',
473
+ alg: kasPublicKey.algorithm,
474
+ type,
442
475
  url: kasPublicKey.url,
443
476
  kid: kasPublicKey.kid,
444
477
  publicKey: kasPublicKey.publicKey,
@@ -457,34 +490,17 @@ export class Client {
457
490
  segmentSizeDefault: windowSize,
458
491
  integrityAlgorithm: 'HS256',
459
492
  segmentIntegrityAlgorithm: 'GMAC',
460
- contentStream: source,
493
+ contentStream: opts.source,
461
494
  mimeType,
462
495
  policy: policyObject,
463
496
  authProvider: this.authProvider,
464
497
  progressHandler: this.clientConfig.progressHandler,
465
498
  keyForEncryption,
466
499
  keyForManifest,
467
- assertionConfigs,
500
+ assertionConfigs: opts.assertionConfigs,
468
501
  };
469
502
 
470
- const stream = await (streamMiddleware as EncryptStreamMiddleware)(await writeStream(ecfg));
471
-
472
- if (!asHtml) {
473
- return stream;
474
- }
475
-
476
- // Wrap if it's html.
477
- if (!stream.manifest) {
478
- throw new Error('internal: missing manifest in encrypt function');
479
- }
480
- const htmlBuf = wrapHtml(await stream.toBuffer(), stream.manifest, this.readerUrl ?? '');
481
-
482
- return new DecoratedReadableStream({
483
- pull(controller: ReadableStreamDefaultController) {
484
- controller.enqueue(htmlBuf);
485
- controller.close();
486
- },
487
- });
503
+ return (streamMiddleware as EncryptStreamMiddleware)(await writeStream(ecfg));
488
504
  }
489
505
 
490
506
  /**
@@ -500,23 +516,28 @@ export class Client {
500
516
  */
501
517
  async decrypt({
502
518
  source,
519
+ allowList,
503
520
  keyMiddleware = async (key: Binary) => key,
504
521
  streamMiddleware = async (stream: DecoratedReadableStream) => stream,
505
522
  assertionVerificationKeys,
506
523
  noVerifyAssertions,
507
524
  concurrencyLimit = 1,
525
+ wrappingKeyAlgorithm,
508
526
  }: DecryptParams): Promise<DecoratedReadableStream> {
509
527
  const dpopKeys = await this.dpopKeys;
510
528
  if (!this.authProvider) {
511
529
  throw new ConfigurationError('AuthProvider missing');
512
530
  }
513
531
  const chunker = await makeChunkable(source);
532
+ if (!allowList) {
533
+ allowList = this.allowedKases;
534
+ }
514
535
 
515
536
  // Await in order to catch any errors from this call.
516
537
  // TODO: Write error event to stream and don't await.
517
538
  return await (streamMiddleware as DecryptStreamMiddleware)(
518
539
  await readStream({
519
- allowList: this.allowedKases,
540
+ allowList,
520
541
  authProvider: this.authProvider,
521
542
  chunker,
522
543
  concurrencyLimit,
@@ -527,6 +548,7 @@ export class Client {
527
548
  progressHandler: this.clientConfig.progressHandler,
528
549
  assertionVerificationKeys,
529
550
  noVerifyAssertions,
551
+ wrappingKeyAlgorithm,
530
552
  })
531
553
  );
532
554
  }
@@ -558,11 +580,4 @@ export class Client {
558
580
 
559
581
  export type { AuthProvider };
560
582
 
561
- export {
562
- DecryptParamsBuilder,
563
- DecryptSource,
564
- EncryptParamsBuilder,
565
- HttpRequest,
566
- fromDataSource,
567
- withHeaders,
568
- };
583
+ export { DecryptParamsBuilder, DecryptSource, EncryptParamsBuilder, HttpRequest, withHeaders };
package/tdf3/src/index.ts CHANGED
@@ -1,4 +1,4 @@
1
1
  export * as Client from './client/index.js';
2
2
  export { Client as TDF3Client } from './client/index.js';
3
3
  export * as Errors from '../../src/errors.js';
4
- export { version, clientType } from './version.js';
4
+ export { clientType, tdfSpecVersion, version } from '../../src/version.js';
@@ -78,7 +78,7 @@ export class SplitKey {
78
78
  }
79
79
 
80
80
  async getKeyAccessObjects(policy: Policy, keyInfo: KeyInfo): Promise<KeyAccessObject[]> {
81
- const splitIds = [...new Set(this.keyAccess.map(({ sid }) => sid))].sort((a, b) =>
81
+ const splitIds = [...new Set(this.keyAccess.map(({ sid }) => sid))].sort((a = '', b = '') =>
82
82
  a.localeCompare(b)
83
83
  );
84
84
  const unwrappedKeySplitBuffers = await keySplit(
@@ -93,7 +93,7 @@ export class SplitKey {
93
93
  const keyAccessObjects = [];
94
94
  for (const item of this.keyAccess) {
95
95
  // use the key split to encrypt metadata for each key access object
96
- const unwrappedKeySplitBuffer = splitsByName[item.sid];
96
+ const unwrappedKeySplitBuffer = splitsByName[item.sid || ''];
97
97
  const unwrappedKeySplitBinary = Binary.fromArrayBuffer(unwrappedKeySplitBuffer.buffer);
98
98
 
99
99
  const metadata = item.metadata || '';
@@ -1,16 +1,19 @@
1
- import { Binary } from '../binary.js';
2
1
  import { base64, hex } from '../../../src/encodings/index.js';
2
+ import { generateRandomNumber } from '../../../src/nanotdf-crypto/generateRandomNumber.js';
3
+ import { keyAgreement } from '../../../src/nanotdf-crypto/keyAgreement.js';
4
+ import { pemPublicToCrypto } from '../../../src/nanotdf-crypto/pemPublicToCrypto.js';
5
+ import { cryptoPublicToPem } from '../../../src/utils.js';
6
+ import { Binary } from '../binary.js';
3
7
  import * as cryptoService from '../crypto/index.js';
4
8
  import { Policy } from './policy.js';
5
9
 
6
- export type KeyAccessType = 'remote' | 'wrapped';
10
+ export type KeyAccessType = 'remote' | 'wrapped' | 'ec-wrapped';
7
11
 
8
- export function isRemote(keyAccessJSON: KeyAccess | KeyAccessObject): boolean {
9
- return keyAccessJSON.type === 'remote';
10
- }
12
+ export const schemaVersion = '1.0';
11
13
 
12
- export class Wrapped {
13
- readonly type = 'wrapped';
14
+ export class ECWrapped {
15
+ readonly type = 'ec-wrapped';
16
+ readonly ephemeralKeyPair: Promise<CryptoKeyPair>;
14
17
  keyAccessObject?: KeyAccessObject;
15
18
 
16
19
  constructor(
@@ -18,60 +21,78 @@ export class Wrapped {
18
21
  public readonly kid: string | undefined,
19
22
  public readonly publicKey: string,
20
23
  public readonly metadata: unknown,
21
- public readonly sid: string
22
- ) {}
24
+ public readonly sid?: string
25
+ ) {
26
+ this.ephemeralKeyPair = crypto.subtle.generateKey(
27
+ {
28
+ name: 'ECDH',
29
+ namedCurve: 'P-256',
30
+ },
31
+ false,
32
+ ['deriveBits', 'deriveKey']
33
+ );
34
+ }
23
35
 
24
36
  async write(
25
37
  policy: Policy,
26
- keyBuffer: Uint8Array,
38
+ dek: Uint8Array,
27
39
  encryptedMetadataStr: string
28
40
  ): Promise<KeyAccessObject> {
29
41
  const policyStr = JSON.stringify(policy);
30
- const unwrappedKeyBinary = Binary.fromArrayBuffer(keyBuffer.buffer);
31
- const wrappedKeyBinary = await cryptoService.encryptWithPublicKey(
32
- unwrappedKeyBinary,
33
- this.publicKey
34
- );
42
+ const [ek, clientPublicKey] = await Promise.all([
43
+ this.ephemeralKeyPair,
44
+ pemPublicToCrypto(this.publicKey),
45
+ ]);
46
+ const kek = await keyAgreement(ek.privateKey, clientPublicKey, {
47
+ hkdfSalt: new TextEncoder().encode('salt'),
48
+ hkdfHash: 'SHA-256',
49
+ });
50
+ const iv = generateRandomNumber(12);
51
+ const cek = await crypto.subtle.encrypt({ name: 'AES-GCM', iv, tagLength: 128 }, kek, dek);
52
+ const entityWrappedKey = new Uint8Array(iv.length + cek.byteLength);
53
+ entityWrappedKey.set(iv);
54
+ entityWrappedKey.set(new Uint8Array(cek), iv.length);
35
55
 
36
56
  const policyBinding = await cryptoService.hmac(
37
- hex.encodeArrayBuffer(keyBuffer),
57
+ hex.encodeArrayBuffer(dek),
38
58
  base64.encode(policyStr)
39
59
  );
40
60
 
41
- this.keyAccessObject = {
42
- type: 'wrapped',
61
+ const ephemeralPublicKeyPEM = await cryptoPublicToPem(ek.publicKey);
62
+ const kao: KeyAccessObject = {
63
+ type: 'ec-wrapped',
43
64
  url: this.url,
44
65
  protocol: 'kas',
45
- wrappedKey: base64.encode(wrappedKeyBinary.asString()),
66
+ wrappedKey: base64.encodeArrayBuffer(entityWrappedKey),
46
67
  encryptedMetadata: base64.encode(encryptedMetadataStr),
47
68
  policyBinding: {
48
69
  alg: 'HS256',
49
70
  hash: base64.encode(policyBinding),
50
71
  },
72
+ schemaVersion,
73
+ ephemeralPublicKey: ephemeralPublicKeyPEM,
51
74
  };
52
75
  if (this.kid) {
53
- this.keyAccessObject.kid = this.kid;
76
+ kao.kid = this.kid;
54
77
  }
55
78
  if (this.sid?.length) {
56
- this.keyAccessObject.sid = this.sid;
79
+ kao.sid = this.sid;
57
80
  }
58
-
59
- return this.keyAccessObject;
81
+ this.keyAccessObject = kao;
82
+ return kao;
60
83
  }
61
84
  }
62
85
 
63
- export class Remote {
64
- readonly type = 'remote';
86
+ export class Wrapped {
87
+ readonly type = 'wrapped';
65
88
  keyAccessObject?: KeyAccessObject;
66
- wrappedKey?: string;
67
- policyBinding?: string;
68
89
 
69
90
  constructor(
70
91
  public readonly url: string,
71
92
  public readonly kid: string | undefined,
72
93
  public readonly publicKey: string,
73
94
  public readonly metadata: unknown,
74
- public readonly sid: string
95
+ public readonly sid?: string
75
96
  ) {}
76
97
 
77
98
  async write(
@@ -80,49 +101,110 @@ export class Remote {
80
101
  encryptedMetadataStr: string
81
102
  ): Promise<KeyAccessObject> {
82
103
  const policyStr = JSON.stringify(policy);
83
- const policyBinding = await cryptoService.hmac(
84
- hex.encodeArrayBuffer(keyBuffer),
85
- base64.encode(policyStr)
86
- );
87
104
  const unwrappedKeyBinary = Binary.fromArrayBuffer(keyBuffer.buffer);
88
105
  const wrappedKeyBinary = await cryptoService.encryptWithPublicKey(
89
106
  unwrappedKeyBinary,
90
107
  this.publicKey
91
108
  );
92
109
 
93
- // this.wrappedKey = wrappedKeyBinary.asBuffer().toString('hex');
94
- this.wrappedKey = base64.encode(wrappedKeyBinary.asString());
110
+ const policyBinding = await cryptoService.hmac(
111
+ hex.encodeArrayBuffer(keyBuffer),
112
+ base64.encode(policyStr)
113
+ );
95
114
 
96
115
  this.keyAccessObject = {
97
- type: 'remote',
116
+ type: 'wrapped',
98
117
  url: this.url,
99
118
  protocol: 'kas',
100
- wrappedKey: this.wrappedKey,
119
+ wrappedKey: base64.encode(wrappedKeyBinary.asString()),
101
120
  encryptedMetadata: base64.encode(encryptedMetadataStr),
102
121
  policyBinding: {
103
122
  alg: 'HS256',
104
123
  hash: base64.encode(policyBinding),
105
124
  },
125
+ schemaVersion,
106
126
  };
107
127
  if (this.kid) {
108
128
  this.keyAccessObject.kid = this.kid;
109
129
  }
130
+ if (this.sid?.length) {
131
+ this.keyAccessObject.sid = this.sid;
132
+ }
133
+
110
134
  return this.keyAccessObject;
111
135
  }
112
136
  }
113
137
 
114
- export type KeyAccess = Remote | Wrapped;
138
+ export type KeyAccess = ECWrapped | Wrapped;
115
139
 
140
+ /**
141
+ * A KeyAccess object stores all information about how an object key OR one key split is stored.
142
+ */
116
143
  export type KeyAccessObject = {
117
- sid?: string;
144
+ /**
145
+ * Specifies how the key is stored. Possible Values:
146
+ * **wrapped**: The wrapped key is stored as part of the manifest.
147
+ * **remote**: [Unsupported] The wrapped key (see below) is stored remotely and is thus not part of the final TDF manifest.
148
+ */
118
149
  type: KeyAccessType;
150
+
151
+ /**
152
+ * A key split (or share) identifier.
153
+ * To allow sharing a key across several access domains,
154
+ * the KAO supports a 'Split Identifier'.
155
+ * To reconstruct such a key when encryptionInformation type is 'split',
156
+ * use the xor operation to combine one of each separate sid.
157
+ */
158
+ sid?: string;
159
+
160
+ /**
161
+ * A locator for a Key Access service capable of granting access to the wrapped key.
162
+ */
119
163
  url: string;
164
+
165
+ /**
166
+ * Additional information for the Key Access service to identify how to unwrap the key.
167
+ */
120
168
  kid?: string;
169
+
170
+ /**
171
+ * The protocol used to access the key.
172
+ */
121
173
  protocol: 'kas';
174
+
175
+ /**
176
+ * The symmetric key used to encrypt the payload.
177
+ * It is encrypted using the public key of the KAS,
178
+ * then base64 encoded.
179
+ */
122
180
  wrappedKey?: string;
181
+
182
+ /**
183
+ * An object that contains a keyed hash that will provide cryptographic integrity on the policy object,
184
+ * such that it cannot be modified or copied to another TDF
185
+ * without invalidating the binding.
186
+ * Specifically, you would have to have access to the key in order to overwrite the policy.
187
+ */
123
188
  policyBinding?: {
124
189
  alg: string;
125
190
  hash: string;
126
191
  };
192
+
193
+ /**
194
+ * Metadata associated with the TDF and the request.
195
+ * The contents of the metadata are freeform,
196
+ * and are used to pass information from the client to the KAS.
197
+ * The metadata stored here should not be used for primary access decisions.
198
+ */
127
199
  encryptedMetadata?: string;
200
+
201
+ /**
202
+ * Version information for the KAO format.
203
+ */
204
+ schemaVersion?: string;
205
+
206
+ /**
207
+ * PEM encoded ephemeral public key, if wrapped with a KAS EC key.
208
+ */
209
+ ephemeralPublicKey?: string;
128
210
  };
@@ -6,4 +6,7 @@ export type Manifest = {
6
6
  payload: Payload;
7
7
  encryptionInformation: EncryptionInformation;
8
8
  assertions: Assertion[];
9
+ schemaVersion: string;
10
+ // Deprecated
11
+ tdf_spec_version?: string;
9
12
  };
@@ -9,7 +9,6 @@ export type PolicyBody = {
9
9
  };
10
10
 
11
11
  export type Policy = {
12
- tdf_spec_version?: string;
13
12
  uuid?: string;
14
13
  body?: PolicyBody;
15
14
  };