@@ -35,7 +35,6 @@ import {
35
35
KeyInfo ,
36
36
Manifest ,
37
37
Policy ,
38
- Remote as KeyAccessRemote ,
39
38
SplitKey ,
40
39
Wrapped as KeyAccessWrapped ,
41
40
KeyAccess ,
@@ -81,8 +80,8 @@ export type BuildKeyAccess = {
81
80
82
81
type Segment = {
83
82
hash : string ;
84
- segmentSize : number | undefined ;
85
- encryptedSegmentSize : number | undefined ;
83
+ segmentSize ? : number ;
84
+ encryptedSegmentSize ? : number ;
86
85
} ;
87
86
88
87
type EntryInfo = {
@@ -92,14 +91,32 @@ type EntryInfo = {
92
91
fileByteCount ?: number ;
93
92
} ;
94
93
94
+ type Mailbox < T > = Promise < T > & {
95
+ set : ( value : T ) => void ;
96
+ reject : ( error : Error ) => void ;
97
+ } ;
98
+
99
+ function mailbox < T > ( ) : Mailbox < T > {
100
+ let set : ( value : T ) => void ;
101
+ let reject : ( error : Error ) => void ;
102
+
103
+ const promise = new Promise < T > ( ( resolve , rejectFn ) => {
104
+ set = resolve ;
105
+ reject = rejectFn ;
106
+ } ) as Mailbox < T > ;
107
+
108
+ promise . set = set ! ;
109
+ promise . reject = reject ! ;
110
+
111
+ return promise ;
112
+ }
113
+
95
114
type Chunk = {
96
115
hash : string ;
116
+ plainSegmentSize ?: number ;
97
117
encryptedOffset : number ;
98
118
encryptedSegmentSize ?: number ;
99
- decryptedChunk ?: null | DecryptResult ;
100
- promise : Promise < unknown > ;
101
- _resolve ?: ( value : unknown ) => void ;
102
- _reject ?: ( value : unknown ) => void ;
119
+ decryptedChunk : Mailbox < DecryptResult > ;
103
120
} ;
104
121
105
122
export type IntegrityAlgorithm = 'GMAC' | 'HS256' ;
@@ -219,10 +236,8 @@ export async function buildKeyAccess({
219
236
switch ( type ) {
220
237
case 'wrapped' :
221
238
return new KeyAccessWrapped ( kasUrl , kasKeyIdentifier , pubKey , metadata , sid ) ;
222
- case 'remote' :
223
- return new KeyAccessRemote ( kasUrl , kasKeyIdentifier , pubKey , metadata , sid ) ;
224
239
default :
225
- throw new ConfigurationError ( `buildKeyAccess: Key access type ${ type } is unknown ` ) ;
240
+ throw new ConfigurationError ( `buildKeyAccess: Key access type [ ${ type } ] is unsupported ` ) ;
226
241
}
227
242
}
228
243
@@ -726,10 +741,10 @@ async function decryptChunk(
726
741
hash : string ,
727
742
cipher : SymmetricCipher ,
728
743
segmentIntegrityAlgorithm : IntegrityAlgorithm ,
729
- cryptoService : CryptoService ,
730
744
isLegacyTDF : boolean
731
745
) : Promise < DecryptResult > {
732
746
if ( segmentIntegrityAlgorithm !== 'GMAC' && segmentIntegrityAlgorithm !== 'HS256' ) {
747
+ throw new UnsupportedError ( `Unsupported integrity alg [${ segmentIntegrityAlgorithm } ]` ) ;
733
748
}
734
749
const segmentSig = await getSignature (
735
750
new Uint8Array ( reconstructedKeyBinary . asArrayBuffer ( ) ) ,
@@ -809,7 +824,6 @@ export async function sliceAndDecrypt({
809
824
reconstructedKeyBinary,
810
825
slice,
811
826
cipher,
812
- cryptoService,
813
827
segmentIntegrityAlgorithm,
814
828
isLegacyTDF,
815
829
} : {
@@ -822,34 +836,35 @@ export async function sliceAndDecrypt({
822
836
isLegacyTDF : boolean ;
823
837
} ) {
824
838
for ( const index in slice ) {
825
- const { encryptedOffset, encryptedSegmentSize, _resolve , _reject } = slice [ index ] ;
839
+ const { encryptedOffset, encryptedSegmentSize, plainSegmentSize } = slice [ index ] ;
826
840
827
841
const offset =
828
842
slice [ 0 ] . encryptedOffset === 0 ? encryptedOffset : encryptedOffset % slice [ 0 ] . encryptedOffset ;
829
843
const encryptedChunk = new Uint8Array (
830
844
buffer . slice ( offset , offset + ( encryptedSegmentSize as number ) )
831
845
) ;
832
846
847
+ if ( encryptedChunk . length !== encryptedSegmentSize ) {
848
+ throw new DecryptError ( 'Failed to fetch entire segment' ) ;
849
+ }
850
+
833
851
try {
834
852
const result = await decryptChunk (
835
853
encryptedChunk ,
836
854
reconstructedKeyBinary ,
837
855
slice [ index ] [ 'hash' ] ,
838
856
cipher ,
839
857
segmentIntegrityAlgorithm ,
840
- cryptoService ,
841
858
isLegacyTDF
842
859
) ;
843
- slice [ index ] . decryptedChunk = result ;
844
- if ( _resolve ) {
845
- _resolve ( null ) ;
860
+ if ( plainSegmentSize && result . payload . length ( ) !== plainSegmentSize ) {
861
+ throw new DecryptError (
862
+ `incorrect segment size: found [${ result . payload . length ( ) } ], expected [${ plainSegmentSize } ]`
863
+ ) ;
846
864
}
865
+ slice [ index ] . decryptedChunk . set ( result ) ;
847
866
} catch ( e ) {
848
- if ( _reject ) {
849
- _reject ( e ) ;
850
- } else {
851
- throw e ;
852
- }
867
+ slice [ index ] . decryptedChunk . reject ( e ) ;
853
868
}
854
869
}
855
870
}
@@ -872,6 +887,7 @@ export async function readStream(cfg: DecryptConfiguration) {
872
887
encryptedSegmentSizeDefault : defaultSegmentSize ,
873
888
rootSignature,
874
889
segmentHashAlg,
890
+ segmentSizeDefault,
875
891
segments,
876
892
} = manifest . encryptionInformation . integrityInformation ;
877
893
const { metadata, reconstructedKeyBinary } = await unwrapKey ( {
@@ -908,14 +924,6 @@ export async function readStream(cfg: DecryptConfiguration) {
908
924
integrityAlgorithm
909
925
) ;
910
926
911
- const rootSig = isLegacyTDF
912
- ? base64 . encode ( hex . encodeArrayBuffer ( payloadSig ) )
913
- : base64 . encodeArrayBuffer ( payloadSig ) ;
914
-
915
- if ( manifest . encryptionInformation . integrityInformation . rootSignature . sig !== rootSig ) {
916
- throw new IntegrityError ( 'Failed integrity check on root signature' ) ;
917
- }
918
-
919
927
if ( ! cfg . noVerifyAssertions ) {
920
928
for ( const assertion of manifest . assertions || [ ] ) {
921
929
// Create a default assertion key
@@ -934,27 +942,36 @@ export async function readStream(cfg: DecryptConfiguration) {
934
942
}
935
943
}
936
944
945
+ const rootSig = isLegacyTDF
946
+ ? base64 . encode ( hex . encodeArrayBuffer ( payloadSig ) )
947
+ : base64 . encodeArrayBuffer ( payloadSig ) ;
948
+
949
+ if ( manifest . encryptionInformation . integrityInformation . rootSignature . sig !== rootSig ) {
950
+ throw new IntegrityError ( 'Failed integrity check on root signature' ) ;
951
+ }
952
+
937
953
let mapOfRequestsOffset = 0 ;
938
954
const chunkMap = new Map (
939
- segments . map ( ( { hash, encryptedSegmentSize = encryptedSegmentSizeDefault } ) => {
940
- const result = ( ( ) => {
941
- let _resolve , _reject ;
942
- const chunk : Chunk = {
943
- hash,
944
- encryptedOffset : mapOfRequestsOffset ,
945
- encryptedSegmentSize,
946
- promise : new Promise ( ( resolve , reject ) => {
947
- _resolve = resolve ;
948
- _reject = reject ;
949
- } ) ,
950
- } ;
951
- chunk . _resolve = _resolve ;
952
- chunk . _reject = _reject ;
953
- return chunk ;
954
- } ) ( ) ;
955
- mapOfRequestsOffset += encryptedSegmentSize || encryptedSegmentSizeDefault ;
956
- return [ hash , result ] ;
957
- } )
955
+ segments . map (
956
+ ( {
957
+ hash,
958
+ encryptedSegmentSize = encryptedSegmentSizeDefault ,
959
+ segmentSize = segmentSizeDefault ,
960
+ } ) => {
961
+ const result = ( ( ) => {
962
+ const chunk : Chunk = {
963
+ hash,
964
+ encryptedOffset : mapOfRequestsOffset ,
965
+ encryptedSegmentSize,
966
+ decryptedChunk : mailbox < DecryptResult > ( ) ,
967
+ plainSegmentSize : segmentSize ,
968
+ } ;
969
+ return chunk ;
970
+ } ) ( ) ;
971
+ mapOfRequestsOffset += encryptedSegmentSize ;
972
+ return [ hash , result ] ;
973
+ }
974
+ )
958
975
) ;
959
976
960
977
const cipher = new AesGcmCipher ( cfg . cryptoService ) ;
@@ -984,16 +1001,11 @@ export async function readStream(cfg: DecryptConfiguration) {
984
1001
}
985
1002
986
1003
const [ hash , chunk ] = chunkMap . entries ( ) . next ( ) . value ;
987
- if ( ! chunk . decryptedChunk ) {
988
- await chunk . promise ;
989
- }
990
- const decryptedSegment = chunk . decryptedChunk ;
1004
+ const decryptedSegment = await chunk . decryptedChunk ;
991
1005
992
1006
controller . enqueue ( new Uint8Array ( decryptedSegment . payload . asByteArray ( ) ) ) ;
993
1007
progress += chunk . encryptedSegmentSize ;
994
1008
cfg . progressHandler ?.( progress ) ;
995
-
996
- chunk . decryptedChunk = null ;
997
1009
chunkMap . delete ( hash ) ;
998
1010
} ,
999
1011
...( cfg . fileStreamServiceWorker && { fileStreamServiceWorker : cfg . fileStreamServiceWorker } ) ,
0 commit comments