@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.
- package/README.md +2 -2
- package/dist/cjs/src/access/access-fetch.js +1 -2
- package/dist/cjs/src/access/access-rpc.js +1 -3
- package/dist/cjs/src/access.js +1 -14
- package/dist/cjs/src/auth/auth.js +13 -10
- package/dist/cjs/src/auth/dpop.js +121 -0
- package/dist/cjs/src/auth/oidc-clientcredentials-provider.js +37 -3
- package/dist/cjs/src/auth/oidc-externaljwt-provider.js +37 -3
- package/dist/cjs/src/auth/oidc-refreshtoken-provider.js +37 -3
- package/dist/cjs/src/auth/oidc.js +10 -8
- package/dist/cjs/src/auth/providers.js +35 -12
- package/dist/cjs/src/crypto/index.js +16 -2
- package/dist/cjs/src/crypto/pemPublicToCrypto.js +17 -11
- package/dist/cjs/src/opentdf.js +50 -13
- package/dist/cjs/src/policy/discovery.js +2 -2
- package/dist/cjs/tdf3/index.js +4 -2
- package/dist/cjs/tdf3/src/assertions.js +71 -31
- package/dist/cjs/tdf3/src/ciphers/aes-gcm-cipher.js +1 -1
- package/dist/cjs/tdf3/src/ciphers/symmetric-cipher-base.js +4 -2
- package/dist/cjs/tdf3/src/client/index.js +23 -33
- package/dist/cjs/tdf3/src/crypto/crypto-utils.js +12 -5
- package/dist/cjs/tdf3/src/crypto/declarations.js +1 -1
- package/dist/cjs/tdf3/src/crypto/index.js +849 -88
- package/dist/cjs/tdf3/src/crypto/jose/jwt-claims-set.js +11 -0
- package/dist/cjs/tdf3/src/crypto/jose/validate-crit.js +8 -0
- package/dist/cjs/tdf3/src/crypto/jose/vendor/lib/buffer_utils.js +41 -0
- package/dist/cjs/tdf3/src/crypto/jose/vendor/lib/epoch.js +6 -0
- package/dist/cjs/tdf3/src/crypto/jose/vendor/lib/is_object.js +21 -0
- package/dist/cjs/tdf3/src/crypto/jose/vendor/lib/jwt_claims_set.js +112 -0
- package/dist/cjs/tdf3/src/crypto/jose/vendor/lib/secs.js +60 -0
- package/dist/cjs/tdf3/src/crypto/jose/vendor/lib/validate_crit.js +38 -0
- package/dist/cjs/tdf3/src/crypto/jose/vendor/util/errors.js +135 -0
- package/dist/cjs/tdf3/src/crypto/jwt.js +183 -0
- package/dist/cjs/tdf3/src/crypto/salt.js +14 -8
- package/dist/cjs/tdf3/src/models/encryption-information.js +17 -20
- package/dist/cjs/tdf3/src/models/key-access.js +43 -63
- package/dist/cjs/tdf3/src/tdf.js +75 -75
- package/dist/cjs/tdf3/src/utils/index.js +5 -39
- package/dist/types/src/access/access-fetch.d.ts.map +1 -1
- package/dist/types/src/access/access-rpc.d.ts.map +1 -1
- package/dist/types/src/access.d.ts +0 -5
- package/dist/types/src/access.d.ts.map +1 -1
- package/dist/types/src/auth/auth.d.ts +9 -6
- package/dist/types/src/auth/auth.d.ts.map +1 -1
- package/dist/types/src/auth/dpop.d.ts +60 -0
- package/dist/types/src/auth/dpop.d.ts.map +1 -0
- package/dist/types/src/auth/oidc-clientcredentials-provider.d.ts +3 -2
- package/dist/types/src/auth/oidc-clientcredentials-provider.d.ts.map +1 -1
- package/dist/types/src/auth/oidc-externaljwt-provider.d.ts +3 -2
- package/dist/types/src/auth/oidc-externaljwt-provider.d.ts.map +1 -1
- package/dist/types/src/auth/oidc-refreshtoken-provider.d.ts +3 -2
- package/dist/types/src/auth/oidc-refreshtoken-provider.d.ts.map +1 -1
- package/dist/types/src/auth/oidc.d.ts +6 -4
- package/dist/types/src/auth/oidc.d.ts.map +1 -1
- package/dist/types/src/auth/providers.d.ts +5 -4
- package/dist/types/src/auth/providers.d.ts.map +1 -1
- package/dist/types/src/crypto/index.d.ts +2 -1
- package/dist/types/src/crypto/index.d.ts.map +1 -1
- package/dist/types/src/crypto/pemPublicToCrypto.d.ts +18 -0
- package/dist/types/src/crypto/pemPublicToCrypto.d.ts.map +1 -1
- package/dist/types/src/opentdf.d.ts +26 -7
- package/dist/types/src/opentdf.d.ts.map +1 -1
- package/dist/types/src/policy/discovery.d.ts +2 -2
- package/dist/types/tdf3/index.d.ts +3 -3
- package/dist/types/tdf3/index.d.ts.map +1 -1
- package/dist/types/tdf3/src/assertions.d.ts +23 -8
- package/dist/types/tdf3/src/assertions.d.ts.map +1 -1
- package/dist/types/tdf3/src/ciphers/aes-gcm-cipher.d.ts +3 -3
- package/dist/types/tdf3/src/ciphers/aes-gcm-cipher.d.ts.map +1 -1
- package/dist/types/tdf3/src/ciphers/symmetric-cipher-base.d.ts +4 -4
- package/dist/types/tdf3/src/ciphers/symmetric-cipher-base.d.ts.map +1 -1
- package/dist/types/tdf3/src/client/builders.d.ts +2 -2
- package/dist/types/tdf3/src/client/builders.d.ts.map +1 -1
- package/dist/types/tdf3/src/client/index.d.ts +6 -5
- package/dist/types/tdf3/src/client/index.d.ts.map +1 -1
- package/dist/types/tdf3/src/crypto/crypto-utils.d.ts +14 -4
- package/dist/types/tdf3/src/crypto/crypto-utils.d.ts.map +1 -1
- package/dist/types/tdf3/src/crypto/declarations.d.ts +283 -18
- package/dist/types/tdf3/src/crypto/declarations.d.ts.map +1 -1
- package/dist/types/tdf3/src/crypto/index.d.ts +105 -28
- package/dist/types/tdf3/src/crypto/index.d.ts.map +1 -1
- package/dist/types/tdf3/src/crypto/jose/jwt-claims-set.d.ts +3 -0
- package/dist/types/tdf3/src/crypto/jose/jwt-claims-set.d.ts.map +1 -0
- package/dist/types/tdf3/src/crypto/jose/validate-crit.d.ts +5 -0
- package/dist/types/tdf3/src/crypto/jose/validate-crit.d.ts.map +1 -0
- package/dist/types/tdf3/src/crypto/jose/vendor/lib/buffer_utils.d.ts +6 -0
- package/dist/types/tdf3/src/crypto/jose/vendor/lib/buffer_utils.d.ts.map +1 -0
- package/dist/types/tdf3/src/crypto/jose/vendor/lib/epoch.d.ts +3 -0
- package/dist/types/tdf3/src/crypto/jose/vendor/lib/epoch.d.ts.map +1 -0
- package/dist/types/tdf3/src/crypto/jose/vendor/lib/is_object.d.ts +3 -0
- package/dist/types/tdf3/src/crypto/jose/vendor/lib/is_object.d.ts.map +1 -0
- package/dist/types/tdf3/src/crypto/jose/vendor/lib/jwt_claims_set.d.ts +3 -0
- package/dist/types/tdf3/src/crypto/jose/vendor/lib/jwt_claims_set.d.ts.map +1 -0
- package/dist/types/tdf3/src/crypto/jose/vendor/lib/secs.d.ts +3 -0
- package/dist/types/tdf3/src/crypto/jose/vendor/lib/secs.d.ts.map +1 -0
- package/dist/types/tdf3/src/crypto/jose/vendor/lib/validate_crit.d.ts +3 -0
- package/dist/types/tdf3/src/crypto/jose/vendor/lib/validate_crit.d.ts.map +1 -0
- package/dist/types/tdf3/src/crypto/jose/vendor/util/errors.d.ts +76 -0
- package/dist/types/tdf3/src/crypto/jose/vendor/util/errors.d.ts.map +1 -0
- package/dist/types/tdf3/src/crypto/jwt.d.ts +76 -0
- package/dist/types/tdf3/src/crypto/jwt.d.ts.map +1 -0
- package/dist/types/tdf3/src/crypto/salt.d.ts +6 -1
- package/dist/types/tdf3/src/crypto/salt.d.ts.map +1 -1
- package/dist/types/tdf3/src/models/encryption-information.d.ts +4 -4
- package/dist/types/tdf3/src/models/encryption-information.d.ts.map +1 -1
- package/dist/types/tdf3/src/models/key-access.d.ts +8 -5
- package/dist/types/tdf3/src/models/key-access.d.ts.map +1 -1
- package/dist/types/tdf3/src/tdf.d.ts +8 -8
- package/dist/types/tdf3/src/tdf.d.ts.map +1 -1
- package/dist/types/tdf3/src/utils/index.d.ts +4 -3
- package/dist/types/tdf3/src/utils/index.d.ts.map +1 -1
- package/dist/web/src/access/access-fetch.js +3 -4
- package/dist/web/src/access/access-rpc.js +3 -5
- package/dist/web/src/access.js +1 -13
- package/dist/web/src/auth/auth.js +13 -10
- package/dist/web/src/auth/dpop.js +118 -0
- package/dist/web/src/auth/oidc-clientcredentials-provider.js +4 -3
- package/dist/web/src/auth/oidc-externaljwt-provider.js +4 -3
- package/dist/web/src/auth/oidc-refreshtoken-provider.js +4 -3
- package/dist/web/src/auth/oidc.js +11 -9
- package/dist/web/src/auth/providers.js +13 -12
- package/dist/web/src/crypto/index.js +4 -2
- package/dist/web/src/crypto/pemPublicToCrypto.js +11 -9
- package/dist/web/src/opentdf.js +17 -13
- package/dist/web/src/policy/discovery.js +2 -2
- package/dist/web/tdf3/index.js +3 -2
- package/dist/web/tdf3/src/assertions.js +71 -31
- package/dist/web/tdf3/src/ciphers/aes-gcm-cipher.js +1 -1
- package/dist/web/tdf3/src/ciphers/symmetric-cipher-base.js +4 -2
- package/dist/web/tdf3/src/client/index.js +25 -35
- package/dist/web/tdf3/src/crypto/crypto-utils.js +12 -5
- package/dist/web/tdf3/src/crypto/declarations.js +1 -1
- package/dist/web/tdf3/src/crypto/index.js +830 -84
- package/dist/web/tdf3/src/crypto/jose/jwt-claims-set.js +5 -0
- package/dist/web/tdf3/src/crypto/jose/validate-crit.js +3 -0
- package/dist/web/tdf3/src/crypto/jose/vendor/lib/buffer_utils.js +35 -0
- package/dist/web/tdf3/src/crypto/jose/vendor/lib/epoch.js +4 -0
- package/dist/web/tdf3/src/crypto/jose/vendor/lib/is_object.js +19 -0
- package/dist/web/tdf3/src/crypto/jose/vendor/lib/jwt_claims_set.js +107 -0
- package/dist/web/tdf3/src/crypto/jose/vendor/lib/secs.js +58 -0
- package/dist/web/tdf3/src/crypto/jose/vendor/lib/validate_crit.js +36 -0
- package/dist/web/tdf3/src/crypto/jose/vendor/util/errors.js +117 -0
- package/dist/web/tdf3/src/crypto/jwt.js +174 -0
- package/dist/web/tdf3/src/crypto/salt.js +13 -7
- package/dist/web/tdf3/src/models/encryption-information.js +11 -14
- package/dist/web/tdf3/src/models/key-access.js +44 -31
- package/dist/web/tdf3/src/tdf.js +71 -71
- package/dist/web/tdf3/src/utils/index.js +5 -6
- package/package.json +11 -4
- package/src/access/access-fetch.ts +2 -8
- package/src/access/access-rpc.ts +0 -7
- package/src/access.ts +0 -17
- package/src/auth/auth.ts +21 -12
- package/src/auth/dpop.ts +222 -0
- package/src/auth/oidc-clientcredentials-provider.ts +23 -15
- package/src/auth/oidc-externaljwt-provider.ts +23 -15
- package/src/auth/oidc-refreshtoken-provider.ts +23 -15
- package/src/auth/oidc.ts +21 -10
- package/src/auth/providers.ts +46 -29
- package/src/crypto/index.ts +21 -1
- package/src/crypto/pemPublicToCrypto.ts +11 -9
- package/src/opentdf.ts +36 -17
- package/src/policy/discovery.ts +2 -2
- package/tdf3/index.ts +32 -5
- package/tdf3/src/assertions.ts +99 -30
- package/tdf3/src/ciphers/aes-gcm-cipher.ts +7 -2
- package/tdf3/src/ciphers/symmetric-cipher-base.ts +7 -4
- package/tdf3/src/client/builders.ts +2 -2
- package/tdf3/src/client/index.ts +60 -59
- package/tdf3/src/crypto/crypto-utils.ts +15 -8
- package/tdf3/src/crypto/declarations.ts +338 -22
- package/tdf3/src/crypto/index.ts +1021 -118
- package/tdf3/src/crypto/jose/jwt-claims-set.ts +10 -0
- package/tdf3/src/crypto/jose/validate-crit.ts +9 -0
- package/tdf3/src/crypto/jose/vendor/lib/buffer_utils.ts +34 -0
- package/tdf3/src/crypto/jose/vendor/lib/epoch.ts +3 -0
- package/tdf3/src/crypto/jose/vendor/lib/is_object.ts +18 -0
- package/tdf3/src/crypto/jose/vendor/lib/jwt_claims_set.ts +106 -0
- package/tdf3/src/crypto/jose/vendor/lib/secs.ts +57 -0
- package/tdf3/src/crypto/jose/vendor/lib/validate_crit.ts +35 -0
- package/tdf3/src/crypto/jose/vendor/util/errors.ts +101 -0
- package/tdf3/src/crypto/jwt.ts +256 -0
- package/tdf3/src/crypto/salt.ts +16 -8
- package/tdf3/src/models/encryption-information.ts +14 -21
- package/tdf3/src/models/key-access.ts +57 -41
- package/tdf3/src/tdf.ts +110 -93
- 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,
|
|
59
|
+
import { ZipReader, ZipWriter, concatUint8, buffToString } from './utils/index.js';
|
|
64
60
|
import { CentralDirectory } from './utils/zip-reader.js';
|
|
65
|
-
import {
|
|
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:
|
|
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:
|
|
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
|
-
|
|
228
|
-
|
|
229
|
-
//
|
|
230
|
-
|
|
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:
|
|
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
|
-
//
|
|
349
|
-
|
|
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
|
-
|
|
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
|
-
|
|
379
|
-
|
|
380
|
-
|
|
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.
|
|
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.
|
|
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
|
-
|
|
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:
|
|
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:
|
|
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.
|
|
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.
|
|
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
|
-
|
|
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:
|
|
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
|
|
781
|
-
let ephemeralEncryptionKeys: PemKeyPair;
|
|
766
|
+
let ephemeralEncryptionKeys: KeyPair;
|
|
782
767
|
if (wrappingKeyAlgorithm === 'ec:secp256r1') {
|
|
783
|
-
|
|
784
|
-
ephemeralEncryptionKeys = await cryptoService.
|
|
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
|
-
|
|
787
|
-
ephemeralEncryptionKeys = await cryptoService.
|
|
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
|
-
|
|
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
|
-
|
|
866
|
-
const
|
|
867
|
-
|
|
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
|
-
|
|
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(
|
|
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
|
-
|
|
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
|
-
|
|
950
|
+
// Merge symmetric keys via CryptoService
|
|
951
|
+
const reconstructedKey = await cryptoService.mergeSymmetricKeys(splitKeys);
|
|
946
952
|
return {
|
|
947
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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,
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1063
|
+
reconstructedKey,
|
|
1056
1064
|
slice,
|
|
1057
1065
|
cipher,
|
|
1066
|
+
cryptoService,
|
|
1058
1067
|
segmentIntegrityAlgorithm,
|
|
1059
1068
|
specVersion,
|
|
1060
1069
|
}: {
|
|
1061
1070
|
buffer: Uint8Array;
|
|
1062
|
-
|
|
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
|
-
|
|
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,
|
|
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(
|
|
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
|
-
|
|
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:
|
|
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(
|
|
1193
|
+
await assertions.verify(
|
|
1194
|
+
assertion,
|
|
1195
|
+
aggregateHash,
|
|
1196
|
+
assertionKey,
|
|
1197
|
+
isLegacyTDF,
|
|
1198
|
+
cfg.cryptoService
|
|
1199
|
+
);
|
|
1183
1200
|
}
|
|
1184
1201
|
}
|
|
1185
1202
|
|
package/tdf3/src/utils/index.ts
CHANGED
|
@@ -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:
|
|
296
|
-
* keyForManifest:
|
|
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(
|
|
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');
|