@opentdf/sdk 0.3.0-beta.2050 → 0.3.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.
- package/dist/cjs/src/opentdf.js +2 -1
- package/dist/cjs/tdf3/src/assertions.js +23 -4
- package/dist/cjs/tdf3/src/client/builders.js +1 -1
- package/dist/cjs/tdf3/src/tdf.js +57 -21
- package/dist/types/src/opentdf.d.ts +1 -0
- package/dist/types/src/opentdf.d.ts.map +1 -1
- package/dist/types/tdf3/src/assertions.d.ts +4 -1
- package/dist/types/tdf3/src/assertions.d.ts.map +1 -1
- package/dist/types/tdf3/src/client/builders.d.ts +2 -0
- package/dist/types/tdf3/src/client/builders.d.ts.map +1 -1
- package/dist/types/tdf3/src/tdf.d.ts +3 -2
- package/dist/types/tdf3/src/tdf.d.ts.map +1 -1
- package/dist/web/src/opentdf.js +2 -1
- package/dist/web/tdf3/src/assertions.js +23 -4
- package/dist/web/tdf3/src/client/builders.js +1 -1
- package/dist/web/tdf3/src/tdf.js +58 -22
- package/package.json +1 -1
- package/src/opentdf.ts +4 -0
- package/tdf3/src/assertions.ts +29 -7
- package/tdf3/src/client/builders.ts +2 -0
- package/tdf3/src/tdf.ts +89 -31
package/tdf3/src/tdf.ts
CHANGED
|
@@ -51,7 +51,7 @@ import {
|
|
|
51
51
|
SplitType,
|
|
52
52
|
} from './models/index.js';
|
|
53
53
|
import { unsigned } from './utils/buffer-crc32.js';
|
|
54
|
-
import { ZipReader, ZipWriter, keyMerge, concatUint8 } from './utils/index.js';
|
|
54
|
+
import { ZipReader, ZipWriter, keyMerge, concatUint8, buffToString } from './utils/index.js';
|
|
55
55
|
import { CentralDirectory } from './utils/zip-reader.js';
|
|
56
56
|
import { ztdfSalt } from './crypto/salt.js';
|
|
57
57
|
import { Payload } from './models/payload.js';
|
|
@@ -59,6 +59,8 @@ import { Payload } from './models/payload.js';
|
|
|
59
59
|
// TODO: input validation on manifest JSON
|
|
60
60
|
const DEFAULT_SEGMENT_SIZE = 1024 * 1024;
|
|
61
61
|
|
|
62
|
+
const HEX_SEMVER_VERSION = '4.2.2';
|
|
63
|
+
|
|
62
64
|
/**
|
|
63
65
|
* Configuration for TDF3
|
|
64
66
|
*/
|
|
@@ -145,6 +147,7 @@ export type EncryptConfiguration = {
|
|
|
145
147
|
keyForEncryption: KeyInfo;
|
|
146
148
|
keyForManifest: KeyInfo;
|
|
147
149
|
assertionConfigs?: AssertionConfig[];
|
|
150
|
+
tdfSpecVersion?: string;
|
|
148
151
|
};
|
|
149
152
|
|
|
150
153
|
export type DecryptConfiguration = {
|
|
@@ -284,7 +287,8 @@ async function _generateManifest(
|
|
|
284
287
|
keyInfo: KeyInfo,
|
|
285
288
|
encryptionInformation: SplitKey,
|
|
286
289
|
policy: Policy,
|
|
287
|
-
mimeType: string | undefined
|
|
290
|
+
mimeType: string | undefined,
|
|
291
|
+
targetSpecVersion: string | undefined
|
|
288
292
|
): Promise<Manifest> {
|
|
289
293
|
// (maybe) Fields are quoted to avoid renaming
|
|
290
294
|
const payload: Payload = {
|
|
@@ -302,7 +306,8 @@ async function _generateManifest(
|
|
|
302
306
|
// generate the manifest first, then insert integrity information into it
|
|
303
307
|
encryptionInformation: encryptionInformationStr,
|
|
304
308
|
assertions: assertions,
|
|
305
|
-
|
|
309
|
+
// when `targetSpecVersion` is provided, overrides the tdfSpecVersion
|
|
310
|
+
schemaVersion: targetSpecVersion || tdfSpecVersion,
|
|
306
311
|
};
|
|
307
312
|
}
|
|
308
313
|
|
|
@@ -335,6 +340,30 @@ async function getSignature(
|
|
|
335
340
|
}
|
|
336
341
|
}
|
|
337
342
|
|
|
343
|
+
async function getSignatureVersion422(
|
|
344
|
+
unwrappedKeyBinary: Binary,
|
|
345
|
+
payloadBinary: Binary,
|
|
346
|
+
algorithmType: IntegrityAlgorithm,
|
|
347
|
+
cryptoService: CryptoService
|
|
348
|
+
): Promise<string> {
|
|
349
|
+
switch (algorithmType.toUpperCase()) {
|
|
350
|
+
case 'GMAC':
|
|
351
|
+
// use the auth tag baked into the encrypted payload
|
|
352
|
+
return buffToString(Uint8Array.from(payloadBinary.asByteArray()).slice(-16), 'hex');
|
|
353
|
+
case 'HS256':
|
|
354
|
+
return await cryptoService.hmac(
|
|
355
|
+
buffToString(new Uint8Array(unwrappedKeyBinary.asArrayBuffer()), 'hex'),
|
|
356
|
+
buffToString(new Uint8Array(payloadBinary.asArrayBuffer()), 'utf-8')
|
|
357
|
+
);
|
|
358
|
+
default:
|
|
359
|
+
throw new ConfigurationError(`Unsupported signature alg [${algorithmType}]`);
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
function isTargetSpecLegacyTDF(targetSpecVersion?: string): boolean {
|
|
364
|
+
return targetSpecVersion === HEX_SEMVER_VERSION;
|
|
365
|
+
}
|
|
366
|
+
|
|
338
367
|
export async function writeStream(cfg: EncryptConfiguration): Promise<DecoratedReadableStream> {
|
|
339
368
|
if (!cfg.authProvider) {
|
|
340
369
|
throw new ConfigurationError('No authorization middleware defined');
|
|
@@ -363,6 +392,7 @@ export async function writeStream(cfg: EncryptConfiguration): Promise<DecoratedR
|
|
|
363
392
|
let bytesProcessed = 0;
|
|
364
393
|
let crcCounter = 0;
|
|
365
394
|
let fileByteCount = 0;
|
|
395
|
+
let aggregateHash422 = '';
|
|
366
396
|
const segmentHashList: Uint8Array[] = [];
|
|
367
397
|
|
|
368
398
|
const zipWriter = new ZipWriter();
|
|
@@ -370,7 +400,8 @@ export async function writeStream(cfg: EncryptConfiguration): Promise<DecoratedR
|
|
|
370
400
|
cfg.keyForManifest,
|
|
371
401
|
cfg.encryptionInformation,
|
|
372
402
|
cfg.policy,
|
|
373
|
-
cfg.mimeType
|
|
403
|
+
cfg.mimeType,
|
|
404
|
+
cfg.tdfSpecVersion ?? '4.3.0'
|
|
374
405
|
);
|
|
375
406
|
|
|
376
407
|
if (!manifest) {
|
|
@@ -455,17 +486,30 @@ export async function writeStream(cfg: EncryptConfiguration): Promise<DecoratedR
|
|
|
455
486
|
crcCounter = 0;
|
|
456
487
|
fileByteCount = 0;
|
|
457
488
|
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
489
|
+
let aggregateHash: string | Uint8Array;
|
|
490
|
+
if (isTargetSpecLegacyTDF(cfg.tdfSpecVersion)) {
|
|
491
|
+
aggregateHash = aggregateHash422;
|
|
492
|
+
const payloadSigStr = await getSignatureVersion422(
|
|
493
|
+
cfg.keyForEncryption.unwrappedKeyBinary,
|
|
494
|
+
Binary.fromString(aggregateHash),
|
|
495
|
+
cfg.integrityAlgorithm,
|
|
496
|
+
cfg.cryptoService
|
|
497
|
+
);
|
|
498
|
+
manifest.encryptionInformation.integrityInformation.rootSignature.sig =
|
|
499
|
+
base64.encode(payloadSigStr);
|
|
500
|
+
} else {
|
|
501
|
+
// hash the concat of all hashes
|
|
502
|
+
aggregateHash = await concatenateUint8Array(segmentHashList);
|
|
503
|
+
|
|
504
|
+
const payloadSig = await getSignature(
|
|
505
|
+
new Uint8Array(cfg.keyForEncryption.unwrappedKeyBinary.asArrayBuffer()),
|
|
506
|
+
aggregateHash,
|
|
507
|
+
cfg.integrityAlgorithm
|
|
508
|
+
);
|
|
466
509
|
|
|
467
|
-
|
|
468
|
-
|
|
510
|
+
const rootSig = base64.encodeArrayBuffer(payloadSig);
|
|
511
|
+
manifest.encryptionInformation.integrityInformation.rootSignature.sig = rootSig;
|
|
512
|
+
}
|
|
469
513
|
manifest.encryptionInformation.integrityInformation.rootSignature.alg =
|
|
470
514
|
cfg.integrityAlgorithm;
|
|
471
515
|
|
|
@@ -571,16 +615,30 @@ export async function writeStream(cfg: EncryptConfiguration): Promise<DecoratedR
|
|
|
571
615
|
cfg.keyForEncryption.unwrappedKeyBinary
|
|
572
616
|
);
|
|
573
617
|
const payloadBuffer = new Uint8Array(encryptedResult.payload.asByteArray());
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
618
|
+
let hash: string;
|
|
619
|
+
if (isTargetSpecLegacyTDF(cfg.tdfSpecVersion)) {
|
|
620
|
+
const payloadSigStr = await getSignatureVersion422(
|
|
621
|
+
cfg.keyForEncryption.unwrappedKeyBinary,
|
|
622
|
+
encryptedResult.payload,
|
|
623
|
+
cfg.segmentIntegrityAlgorithm,
|
|
624
|
+
cfg.cryptoService
|
|
625
|
+
);
|
|
626
|
+
// combined string of all hashes for root signature
|
|
627
|
+
aggregateHash422 += payloadSigStr;
|
|
628
|
+
hash = base64.encode(payloadSigStr);
|
|
629
|
+
} else {
|
|
630
|
+
const payloadSig = await getSignature(
|
|
631
|
+
new Uint8Array(cfg.keyForEncryption.unwrappedKeyBinary.asArrayBuffer()),
|
|
632
|
+
new Uint8Array(encryptedResult.payload.asArrayBuffer()),
|
|
633
|
+
cfg.segmentIntegrityAlgorithm
|
|
634
|
+
);
|
|
579
635
|
|
|
580
|
-
|
|
636
|
+
segmentHashList.push(new Uint8Array(payloadSig));
|
|
637
|
+
hash = base64.encodeArrayBuffer(payloadSig);
|
|
638
|
+
}
|
|
581
639
|
|
|
582
640
|
segmentInfos.push({
|
|
583
|
-
hash
|
|
641
|
+
hash,
|
|
584
642
|
segmentSize: chunk.length === segmentSizeDefault ? undefined : chunk.length,
|
|
585
643
|
encryptedSegmentSize:
|
|
586
644
|
payloadBuffer.length === encryptedSegmentSizeDefault ? undefined : payloadBuffer.length,
|
|
@@ -790,7 +848,7 @@ async function decryptChunk(
|
|
|
790
848
|
hash: string,
|
|
791
849
|
cipher: SymmetricCipher,
|
|
792
850
|
segmentIntegrityAlgorithm: IntegrityAlgorithm,
|
|
793
|
-
|
|
851
|
+
specVersion: string
|
|
794
852
|
): Promise<DecryptResult> {
|
|
795
853
|
if (segmentIntegrityAlgorithm !== 'GMAC' && segmentIntegrityAlgorithm !== 'HS256') {
|
|
796
854
|
throw new UnsupportedError(`Unsupported integrity alg [${segmentIntegrityAlgorithm}]`);
|
|
@@ -801,7 +859,7 @@ async function decryptChunk(
|
|
|
801
859
|
segmentIntegrityAlgorithm
|
|
802
860
|
);
|
|
803
861
|
|
|
804
|
-
const segmentHash =
|
|
862
|
+
const segmentHash = isTargetSpecLegacyTDF(specVersion)
|
|
805
863
|
? base64.encode(hex.encodeArrayBuffer(segmentSig))
|
|
806
864
|
: base64.encodeArrayBuffer(segmentSig);
|
|
807
865
|
|
|
@@ -819,7 +877,7 @@ async function updateChunkQueue(
|
|
|
819
877
|
cipher: SymmetricCipher,
|
|
820
878
|
segmentIntegrityAlgorithm: IntegrityAlgorithm,
|
|
821
879
|
cryptoService: CryptoService,
|
|
822
|
-
|
|
880
|
+
specVersion: string
|
|
823
881
|
) {
|
|
824
882
|
const chunksInOneDownload = 500;
|
|
825
883
|
let requests = [];
|
|
@@ -860,7 +918,7 @@ async function updateChunkQueue(
|
|
|
860
918
|
slice,
|
|
861
919
|
cipher,
|
|
862
920
|
segmentIntegrityAlgorithm,
|
|
863
|
-
|
|
921
|
+
specVersion,
|
|
864
922
|
});
|
|
865
923
|
}
|
|
866
924
|
})()
|
|
@@ -874,7 +932,7 @@ export async function sliceAndDecrypt({
|
|
|
874
932
|
slice,
|
|
875
933
|
cipher,
|
|
876
934
|
segmentIntegrityAlgorithm,
|
|
877
|
-
|
|
935
|
+
specVersion,
|
|
878
936
|
}: {
|
|
879
937
|
buffer: Uint8Array;
|
|
880
938
|
reconstructedKeyBinary: Binary;
|
|
@@ -882,7 +940,7 @@ export async function sliceAndDecrypt({
|
|
|
882
940
|
cipher: SymmetricCipher;
|
|
883
941
|
cryptoService: CryptoService;
|
|
884
942
|
segmentIntegrityAlgorithm: IntegrityAlgorithm;
|
|
885
|
-
|
|
943
|
+
specVersion: string;
|
|
886
944
|
}) {
|
|
887
945
|
for (const index in slice) {
|
|
888
946
|
const { encryptedOffset, encryptedSegmentSize, plainSegmentSize } = slice[index];
|
|
@@ -904,7 +962,7 @@ export async function sliceAndDecrypt({
|
|
|
904
962
|
slice[index]['hash'],
|
|
905
963
|
cipher,
|
|
906
964
|
segmentIntegrityAlgorithm,
|
|
907
|
-
|
|
965
|
+
specVersion
|
|
908
966
|
);
|
|
909
967
|
if (plainSegmentSize && result.payload.length() !== plainSegmentSize) {
|
|
910
968
|
throw new DecryptError(
|
|
@@ -960,8 +1018,8 @@ export async function decryptStreamFrom(
|
|
|
960
1018
|
const encryptedSegmentSizeDefault = defaultSegmentSize || DEFAULT_SEGMENT_SIZE;
|
|
961
1019
|
|
|
962
1020
|
// check if the TDF is a legacy TDF
|
|
963
|
-
const specVersion = manifest.schemaVersion || manifest.tdf_spec_version;
|
|
964
|
-
const isLegacyTDF =
|
|
1021
|
+
const specVersion = manifest.schemaVersion || manifest.tdf_spec_version || '4.2.2';
|
|
1022
|
+
const isLegacyTDF = isTargetSpecLegacyTDF(specVersion);
|
|
965
1023
|
|
|
966
1024
|
// Decode each hash and store it in an array of Uint8Array
|
|
967
1025
|
const segmentHashList = segments.map(
|
|
@@ -1047,7 +1105,7 @@ export async function decryptStreamFrom(
|
|
|
1047
1105
|
cipher,
|
|
1048
1106
|
segmentIntegrityAlg,
|
|
1049
1107
|
cfg.cryptoService,
|
|
1050
|
-
|
|
1108
|
+
specVersion
|
|
1051
1109
|
);
|
|
1052
1110
|
|
|
1053
1111
|
let progress = 0;
|