summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGregory P. Smith <greg@mad-scientist.com>2008-01-20 01:21:03 (GMT)
committerGregory P. Smith <greg@mad-scientist.com>2008-01-20 01:21:03 (GMT)
commit0c63fc23c4ca5b859a99e0d1864a41df6cc08d5f (patch)
treeeabd8e15d1ea200d40b53b085be214d3d62d01f3
parent88fbcf82ab49d91dab416a6e3bbfb6bb535c86c1 (diff)
downloadcpython-0c63fc23c4ca5b859a99e0d1864a41df6cc08d5f.zip
cpython-0c63fc23c4ca5b859a99e0d1864a41df6cc08d5f.tar.gz
cpython-0c63fc23c4ca5b859a99e0d1864a41df6cc08d5f.tar.bz2
Fix zipfile decryption. The check for validity only worked on one
type of encrypted zip files. Files using extended local headers needed to compare the check byte against different values. (according to reading the infozip unzip crypt.c source code) Fixes issue1003.
-rw-r--r--Lib/test/test_zipfile.py21
-rw-r--r--Lib/zipfile.py13
2 files changed, 32 insertions, 2 deletions
diff --git a/Lib/test/test_zipfile.py b/Lib/test/test_zipfile.py
index 40003aa..adc0dc1 100644
--- a/Lib/test/test_zipfile.py
+++ b/Lib/test/test_zipfile.py
@@ -698,31 +698,52 @@ class DecryptionTests(unittest.TestCase):
'\x1a\x00\x00\x00\x08\x00\x00\x00\x00\x00\x00\x00\x01\x00 \x00\xb6\x81'
'\x00\x00\x00\x00test.txtPK\x05\x06\x00\x00\x00\x00\x01\x00\x01\x006\x00'
'\x00\x00L\x00\x00\x00\x00\x00' )
+ data2 = (
+ 'PK\x03\x04\x14\x00\t\x00\x08\x00\xcf}38xu\xaa\xb2\x14\x00\x00\x00\x00\x02'
+ '\x00\x00\x04\x00\x15\x00zeroUT\t\x00\x03\xd6\x8b\x92G\xda\x8b\x92GUx\x04'
+ '\x00\xe8\x03\xe8\x03\xc7<M\xb5a\xceX\xa3Y&\x8b{oE\xd7\x9d\x8c\x98\x02\xc0'
+ 'PK\x07\x08xu\xaa\xb2\x14\x00\x00\x00\x00\x02\x00\x00PK\x01\x02\x17\x03'
+ '\x14\x00\t\x00\x08\x00\xcf}38xu\xaa\xb2\x14\x00\x00\x00\x00\x02\x00\x00'
+ '\x04\x00\r\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa4\x81\x00\x00\x00\x00ze'
+ 'roUT\x05\x00\x03\xd6\x8b\x92GUx\x00\x00PK\x05\x06\x00\x00\x00\x00\x01'
+ '\x00\x01\x00?\x00\x00\x00[\x00\x00\x00\x00\x00' )
plain = 'zipfile.py encryption test'
+ plain2 = '\x00'*512
def setUp(self):
fp = open(TESTFN, "wb")
fp.write(self.data)
fp.close()
self.zip = zipfile.ZipFile(TESTFN, "r")
+ fp = open(TESTFN2, "wb")
+ fp.write(self.data2)
+ fp.close()
+ self.zip2 = zipfile.ZipFile(TESTFN2, "r")
def tearDown(self):
self.zip.close()
os.unlink(TESTFN)
+ self.zip2.close()
+ os.unlink(TESTFN2)
def testNoPassword(self):
# Reading the encrypted file without password
# must generate a RunTime exception
self.assertRaises(RuntimeError, self.zip.read, "test.txt")
+ self.assertRaises(RuntimeError, self.zip2.read, "zero")
def testBadPassword(self):
self.zip.setpassword("perl")
self.assertRaises(RuntimeError, self.zip.read, "test.txt")
+ self.zip2.setpassword("perl")
+ self.assertRaises(RuntimeError, self.zip2.read, "zero")
def testGoodPassword(self):
self.zip.setpassword("python")
self.assertEquals(self.zip.read("test.txt"), self.plain)
+ self.zip2.setpassword("12345")
+ self.assertEquals(self.zip2.read("zero"), self.plain2)
class TestsWithRandomBinaryFiles(unittest.TestCase):
diff --git a/Lib/zipfile.py b/Lib/zipfile.py
index eb00b34..6feabbf 100644
--- a/Lib/zipfile.py
+++ b/Lib/zipfile.py
@@ -186,6 +186,7 @@ class ZipInfo (object):
'CRC',
'compress_size',
'file_size',
+ '_raw_time',
)
def __init__(self, filename="NoName", date_time=(1980,1,1,0,0,0)):
@@ -683,6 +684,7 @@ class ZipFile:
x.CRC, x.compress_size, x.file_size) = centdir[1:12]
x.volume, x.internal_attr, x.external_attr = centdir[15:18]
# Convert date/time code to (year, month, day, hour, min, sec)
+ x._raw_time = t
x.date_time = ( (d>>9)+1980, (d>>5)&0xF, d&0x1F,
t>>11, (t>>5)&0x3F, (t&0x1F) * 2 )
@@ -790,11 +792,18 @@ class ZipFile:
# The first 12 bytes in the cypher stream is an encryption header
# used to strengthen the algorithm. The first 11 bytes are
# completely random, while the 12th contains the MSB of the CRC,
+ # or the MSB of the file time depending on the header type
# and is used to check the correctness of the password.
bytes = zef_file.read(12)
h = map(zd, bytes[0:12])
- if ord(h[11]) != ((zinfo.CRC>>24)&255):
- raise RuntimeError, "Bad password for file %s" % name
+ if zinfo.flag_bits & 0x8:
+ # compare against the file type from extended local headers
+ check_byte = (zinfo._raw_time >> 8) & 0xff
+ else:
+ # compare against the CRC otherwise
+ check_byte = (zinfo.CRC >> 24) & 0xff
+ if ord(h[11]) != check_byte:
+ raise RuntimeError("Bad password for file", name)
# build and return a ZipExtFile
if zd is None: