@@ -784,10 +784,10 @@ class ZipExtFile(io.BufferedIOBase):
784784 # Chunk size to read during seek
785785 MAX_SEEK_READ = 1 << 24
786786
787- def __init__ (self , fileobj , mode , zipinfo , decrypter = None ,
787+ def __init__ (self , fileobj , mode , zipinfo , pwd = None ,
788788 close_fileobj = False ):
789789 self ._fileobj = fileobj
790- self ._decrypter = decrypter
790+ self ._pwd = pwd
791791 self ._close_fileobj = close_fileobj
792792
793793 self ._compress_type = zipinfo .compress_type
@@ -802,11 +802,6 @@ def __init__(self, fileobj, mode, zipinfo, decrypter=None,
802802
803803 self .newlines = None
804804
805- # Adjust read size for encrypted files since the first 12 bytes
806- # are for the encryption/password information.
807- if self ._decrypter is not None :
808- self ._compress_left -= 12
809-
810805 self .mode = mode
811806 self .name = zipinfo .filename
812807
@@ -827,6 +822,30 @@ def __init__(self, fileobj, mode, zipinfo, decrypter=None,
827822 except AttributeError :
828823 pass
829824
825+ self ._decrypter = None
826+ if pwd :
827+ if zipinfo .flag_bits & 0x8 :
828+ # compare against the file type from extended local headers
829+ check_byte = (zipinfo ._raw_time >> 8 ) & 0xff
830+ else :
831+ # compare against the CRC otherwise
832+ check_byte = (zipinfo .CRC >> 24 ) & 0xff
833+ h = self ._init_decrypter ()
834+ if h != check_byte :
835+ raise RuntimeError ("Bad password for file %r" % zipinfo .orig_filename )
836+
837+
838+ def _init_decrypter (self ):
839+ self ._decrypter = _ZipDecrypter (self ._pwd )
840+ # The first 12 bytes in the cypher stream is an encryption header
841+ # used to strengthen the algorithm. The first 11 bytes are
842+ # completely random, while the 12th contains the MSB of the CRC,
843+ # or the MSB of the file time depending on the header type
844+ # and is used to check the correctness of the password.
845+ header = self ._fileobj .read (12 )
846+ self ._compress_left -= 12
847+ return self ._decrypter (header )[11 ]
848+
830849 def __repr__ (self ):
831850 result = ['<%s.%s' % (self .__class__ .__module__ ,
832851 self .__class__ .__qualname__ )]
@@ -1053,6 +1072,8 @@ def seek(self, offset, whence=0):
10531072 self ._decompressor = _get_decompressor (self ._compress_type )
10541073 self ._eof = False
10551074 read_offset = new_pos
1075+ if self ._decrypter is not None :
1076+ self ._init_decrypter ()
10561077
10571078 while read_offset > 0 :
10581079 read_len = min (self .MAX_SEEK_READ , read_offset )
@@ -1515,32 +1536,16 @@ def open(self, name, mode="r", pwd=None, *, force_zip64=False):
15151536
15161537 # check for encrypted flag & handle password
15171538 is_encrypted = zinfo .flag_bits & 0x1
1518- zd = None
15191539 if is_encrypted :
15201540 if not pwd :
15211541 pwd = self .pwd
15221542 if not pwd :
15231543 raise RuntimeError ("File %r is encrypted, password "
15241544 "required for extraction" % name )
1545+ else :
1546+ pwd = None
15251547
1526- zd = _ZipDecrypter (pwd )
1527- # The first 12 bytes in the cypher stream is an encryption header
1528- # used to strengthen the algorithm. The first 11 bytes are
1529- # completely random, while the 12th contains the MSB of the CRC,
1530- # or the MSB of the file time depending on the header type
1531- # and is used to check the correctness of the password.
1532- header = zef_file .read (12 )
1533- h = zd (header [0 :12 ])
1534- if zinfo .flag_bits & 0x8 :
1535- # compare against the file type from extended local headers
1536- check_byte = (zinfo ._raw_time >> 8 ) & 0xff
1537- else :
1538- # compare against the CRC otherwise
1539- check_byte = (zinfo .CRC >> 24 ) & 0xff
1540- if h [11 ] != check_byte :
1541- raise RuntimeError ("Bad password for file %r" % name )
1542-
1543- return ZipExtFile (zef_file , mode , zinfo , zd , True )
1548+ return ZipExtFile (zef_file , mode , zinfo , pwd , True )
15441549 except :
15451550 zef_file .close ()
15461551 raise
0 commit comments