@@ -792,10 +792,10 @@ class ZipExtFile(io.BufferedIOBase):
792
792
# Chunk size to read during seek
793
793
MAX_SEEK_READ = 1 << 24
794
794
795
- def __init__ (self , fileobj , mode , zipinfo , decrypter = None ,
795
+ def __init__ (self , fileobj , mode , zipinfo , pwd = None ,
796
796
close_fileobj = False ):
797
797
self ._fileobj = fileobj
798
- self ._decrypter = decrypter
798
+ self ._pwd = pwd
799
799
self ._close_fileobj = close_fileobj
800
800
801
801
self ._compress_type = zipinfo .compress_type
@@ -810,11 +810,6 @@ def __init__(self, fileobj, mode, zipinfo, decrypter=None,
810
810
811
811
self .newlines = None
812
812
813
- # Adjust read size for encrypted files since the first 12 bytes
814
- # are for the encryption/password information.
815
- if self ._decrypter is not None :
816
- self ._compress_left -= 12
817
-
818
813
self .mode = mode
819
814
self .name = zipinfo .filename
820
815
@@ -835,6 +830,30 @@ def __init__(self, fileobj, mode, zipinfo, decrypter=None,
835
830
except AttributeError :
836
831
pass
837
832
833
+ self ._decrypter = None
834
+ if pwd :
835
+ if zipinfo .flag_bits & 0x8 :
836
+ # compare against the file type from extended local headers
837
+ check_byte = (zipinfo ._raw_time >> 8 ) & 0xff
838
+ else :
839
+ # compare against the CRC otherwise
840
+ check_byte = (zipinfo .CRC >> 24 ) & 0xff
841
+ h = self ._init_decrypter ()
842
+ if h != check_byte :
843
+ raise RuntimeError ("Bad password for file %r" % zipinfo .orig_filename )
844
+
845
+
846
+ def _init_decrypter (self ):
847
+ self ._decrypter = _ZipDecrypter (self ._pwd )
848
+ # The first 12 bytes in the cypher stream is an encryption header
849
+ # used to strengthen the algorithm. The first 11 bytes are
850
+ # completely random, while the 12th contains the MSB of the CRC,
851
+ # or the MSB of the file time depending on the header type
852
+ # and is used to check the correctness of the password.
853
+ header = self ._fileobj .read (12 )
854
+ self ._compress_left -= 12
855
+ return self ._decrypter (header )[11 ]
856
+
838
857
def __repr__ (self ):
839
858
result = ['<%s.%s' % (self .__class__ .__module__ ,
840
859
self .__class__ .__qualname__ )]
@@ -1061,6 +1080,8 @@ def seek(self, offset, whence=0):
1061
1080
self ._decompressor = _get_decompressor (self ._compress_type )
1062
1081
self ._eof = False
1063
1082
read_offset = new_pos
1083
+ if self ._decrypter is not None :
1084
+ self ._init_decrypter ()
1064
1085
1065
1086
while read_offset > 0 :
1066
1087
read_len = min (self .MAX_SEEK_READ , read_offset )
@@ -1524,32 +1545,16 @@ def open(self, name, mode="r", pwd=None, *, force_zip64=False):
1524
1545
1525
1546
# check for encrypted flag & handle password
1526
1547
is_encrypted = zinfo .flag_bits & 0x1
1527
- zd = None
1528
1548
if is_encrypted :
1529
1549
if not pwd :
1530
1550
pwd = self .pwd
1531
1551
if not pwd :
1532
1552
raise RuntimeError ("File %r is encrypted, password "
1533
1553
"required for extraction" % name )
1554
+ else :
1555
+ pwd = None
1534
1556
1535
- zd = _ZipDecrypter (pwd )
1536
- # The first 12 bytes in the cypher stream is an encryption header
1537
- # used to strengthen the algorithm. The first 11 bytes are
1538
- # completely random, while the 12th contains the MSB of the CRC,
1539
- # or the MSB of the file time depending on the header type
1540
- # and is used to check the correctness of the password.
1541
- header = zef_file .read (12 )
1542
- h = zd (header [0 :12 ])
1543
- if zinfo .flag_bits & 0x8 :
1544
- # compare against the file type from extended local headers
1545
- check_byte = (zinfo ._raw_time >> 8 ) & 0xff
1546
- else :
1547
- # compare against the CRC otherwise
1548
- check_byte = (zinfo .CRC >> 24 ) & 0xff
1549
- if h [11 ] != check_byte :
1550
- raise RuntimeError ("Bad password for file %r" % name )
1551
-
1552
- return ZipExtFile (zef_file , mode , zinfo , zd , True )
1557
+ return ZipExtFile (zef_file , mode , zinfo , pwd , True )
1553
1558
except :
1554
1559
zef_file .close ()
1555
1560
raise
0 commit comments