What I found in the documentation for zipfile
is that the library supports decryption only with a password. It cannot encrypt. So you won't be able to add files with a password.
It supports decryption of encrypted files in ZIP archives, but it currently cannot create an encrypted file.
https://docs.python.org/3/library/zipfile.html
EDIT: Further, looking into python bugs Issue 34546: Add encryption support to zipfile it appears that in order to not perpetuate a weak password scheme that is used in zip, they opted to not include it.
Something that you could do is utilize subprocess
to add files with a password.
Further, if you wanted to "validate" the entered password first, you could do something like this but you'd have to know the contents of the file because decrypt will happily decrypt any file with any password, the plaintext result will just be not correct.
Issues you'll have to solved:
- Comparing file contents to validate password
- Handling when a file exists already in the zip file
- handling when the zipfile already exists AND when it doesn't.
import subprocess
import zipfile
def zip_file(zipFilename, filename):
zipPass = str(input("Please enter the zip password: "))
zipPass = bytes(zipPass, encoding='utf-8')
#If there is a file that we know the plain-text (or original binary)
#TODO: handle fipFilename not existing.
validPass=False
with zipfile.ZipFile(zipFilename, 'r') as zFile:
zFile.setpassword(zipPass)
with zFile.open('known.txt') as knownFile:
#TODO: compare contents of known.txt with actual
validPass=True
#Next to add file with password cannot use zipfile because password not supported
# Note this is a linux only solution, os dependency will need to be checked
#if compare was ok, then valid password?
if not validPass:
print('Invalid Password')
else:
#TODO: handle zipfile not-exist and existing may have to pass
# different flags.
#TODO: handle filename existing in zipFilename
#WARNING the linux manual page for 'zip' states -P is UNSECURE.
res = subprocess.run(['zip', '-e', '-P', zipPass, zipFilename, filename])
#TODO: Check res for success or failure.
EDIT:
I looked into fixing the whole "exposed password" issue with -P
. Unfortunately, it is non trivial. You cannot simply write zipPass
into the stdin of the subprocess.run
with input=
. I think something like pexpect
might be a solution for this, but I haven't spent the time to make that work. See here for example of how to use pexpect
to accomplish this: Use subprocess to send a password_