How to zip a folder in python with password?

Question:

With pyminizip i am able to zip a file with password in python :

filepath=r"C:UsersxxxDesktopmyFolderfile.txt"

import pyminizip
pyminizip.compress(filepath, None,"output.zip", "password", 0)

But how do I zip the whole folder ‘myFolder’ into a zip file with password?
I tried removing the filename from the path but it gives the error

OSError: error in opening C:UsersxxxDesktopmyFolder for reading

EDIT :

The below link has a function which will zip the directory. But It wont add a password.

https://www.calazan.com/how-to-zip-an-entire-directory-with-python/

If anyone can let me know if it is possible to add a password to an existing zip file, that will solve my problem. Is that possible?

Asked By: anandhu

||

Answers:

Try this:
Firstly check here please for pynzip. After that try it.

import pyminizip as pyzip

compression = 8
pyzip.compress("test.txt", "test.zip", "Pswrd", compression)
Answered By: inspired

I was finally able to accomplish encryping the whole directory(including all subfolder struncture and files) using a library called ‘pyzipper’ suggested by Anupam Chaplot.

Here is the solution :

def zip_folderPyzipper(folder_path, output_path):
    """Zip the contents of an entire folder (with that folder included
    in the archive). Empty subfolders will be included in the archive
    as well.
    """
    parent_folder = os.path.dirname(folder_path)
    # Retrieve the paths of the folder contents.
    contents = os.walk(folder_path)
    try:
        zip_file = pyzipper.AESZipFile('new_test.zip','w',compression=pyzipper.ZIP_DEFLATED,encryption=pyzipper.WZ_AES)
        zip_file.pwd=b'PASSWORD'
        for root, folders, files in contents:
            # Include all subfolders, including empty ones.
            for folder_name in folders:
                absolute_path = os.path.join(root, folder_name)
                relative_path = absolute_path.replace(parent_folder + '\',
                                                      '')
                print ("Adding '%s' to archive." % absolute_path)
                zip_file.write(absolute_path, relative_path)
            for file_name in files:
                absolute_path = os.path.join(root, file_name)
                relative_path = absolute_path.replace(parent_folder + '\',
                                                      '')
                print ("Adding '%s' to archive." % absolute_path)
                zip_file.write(absolute_path, relative_path)

        print ("'%s' created successfully." % output_path)

    except IOError as message:
        print (message)
        sys.exit(1)
    except OSError as message:
        print(message)
        sys.exit(1)
    except zipfile.BadZipfile as message:
        print (message)
        sys.exit(1)
    finally:
        zip_file.close()

Since I am new in python i cant explain the code in detail. Here are the references :

https://pypi.org/project/pyzipper/

https://www.calazan.com/how-to-zip-an-entire-directory-with-python/

To extract the Generated ZIP file in windows :

Right Click – > Unzip(Encripted)

If you directly click Extract All option, then it will give error

Answered By: anandhu

Here is how to copy all a directory with its subdirectories and its files, then compress it and encrypt a zip, with password and without needing an associated backup file, here we will see how to authorize a mac address to execute the decryption. So then it’s up to you to change or improve the script.
But the essentials work very well.
After a lot of research, testing and thinking, I created this effective solution

my setup:
Python 3.8 64:bits on windows 7 64:bits

Usage terminology:

First step, we need to import the cryptography module
check for support or other is here https://cryptography.io/en/latest/installation/
command:
pip install cryptography

Then we will use the fernet object resulting from this module
https://cryptography.io/en/latest/fernet/

with password
https://cryptography.io/en/latest/fernet/#using-passwords-with-fernet

and shutil:
https://docs.python.org/3/library/shutil.html
file second.py:

import os
import re, uuid
import string
import shutil
import zlib
from cryptography.fernet import Fernet
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
import base64
import zipfile

class zipy:
    def __init__(self, pathDir=None):
        """If pathDir optional is none, this script copy all directory in current execution."""
        if pathDir != None:
            if os.path.isdir(pathDir):
                pathDir = pathDir.replace(os.sep, '/')
                if pathDir.endswith('/'):
                    self.root = pathDir
                else:
                    self.root = pathDir + '/'
            else:
                self.root = os.getcwd()+os.sep
                self.root = self.root.replace(os.sep, '/')
        else:
            self.root = os.getcwd()+os.sep
            self.root = self.root.replace(os.sep, '/')
            
        os.chdir(self.root)
        
        self.name = 'sauvegarde'
        self.dirSauvegarde = self.root+self.name
        self.dirSauvegarde = self.dirSauvegarde.replace(os.sep, '/')
        lectureDossier = os.listdir(self.root)
        print(lectureDossier)
        self.path_system = {}
        for element in lectureDossier:
            if os.path.isdir(element):
                if element != '__pycache__':
                    self.path_system[element] = self.root + element + os.sep.replace(os.sep, '/')
                    self.path_system[element] = self.path_system[element].replace(os.sep, '/')
                else:
                    pass
            elif os.path.isfile(element):
                self.path_system[element] = self.root + element
                self.path_system[element] = self.path_system[element].replace(os.sep, '/')
            else:
                pass
        self.zipi = myZip(self.dirSauvegarde)
        
    def save(self):
        """sauvegarde le fichier"""
        self.createDir(self.dirSauvegarde)
        chemin_src = ""
        chemin_dist = ""
        for element in self.path_system:
            if element != self.dirSauvegarde:
                chemin_src = self.root+element
                chemin_dest = self.dirSauvegarde + os.sep + element
                chemin_dest = chemin_dest.replace(os.sep, '/')
                if os.path.isdir(chemin_src):
                    self.copyDir(chemin_src, chemin_dest)
                else:
                    self.copyFile(chemin_src, chemin_dest)
        self.zipi.zip(zip_exist=True)
        self.delDir(self.dirSauvegarde)
    
    def copyDir(self, src, dest):
        try:
            shutil.copytree(src, dest, dirs_exist_ok=True)
        except:
            pass
            
    def copyFile(self, src, dest):
        try:
            shutil.copyfile(src, dest)
        except:
            pass
            
    def createDir(self, dirPath):
        if os.path.isdir(dirPath):
            self.delDir(dirPath)
        else:
            pass
            
        os.makedirs(dirPath, exist_ok=True)
            
    def delDir(self, dir):
        if os.path.isdir(dir):
            if len(os.listdir(dir)) > 0:
                try:
                   print('rmtree')
                   shutil.rmtree(dir, ignore_errors=True)
                except:
                   pass
            else:
                try:
                   os.rmdir(dir)
                except:
                   pass
                   
    def decrypt(self):
        self.zipi.unzip()
        
class myZip:
    def __init__(self, dir):
        self.pathDir = dir
        self.nom = os.path.basename(dir)
        self.pathZip = self.pathDir + '.zip'
        self.crypt = Encryptor()
        
    def zip(self, zip_exist=False):
        if zip_exist == False:
            pass
        else:
            if os.path.isfile(self.pathZip):
                try:
                    os.remove(self.pathZip)
                except:
                    pass
        shutil.make_archive(os.path.splitext(self.pathZip)[0], 'zip', self.pathDir)
        key = self.crypt.key_create()
        #TEST
        self.crypt.file_encrypt(key, self.pathZip, self.pathZip)
        self.crypt.key_write(self.pathZip, key)
        
        
    def unzip(self):
        #TEST
        if self.crypt.checkPass(self.pathZip):
            #print('ok adresse mac autoriser')
            key = self.crypt.key_load(self.pathZip)
            self.crypt.file_decrypt(key, self.pathZip, self.pathZip)
        else:
            print('pas ok adresse mac erroner')

class Encryptor:

    def __init__(self):
        self.salto = None

    def key_create(self):
        password = self.getMac()
        password = bytes(password, encoding="utf-8")

        self.salto = os.urandom(16)
        print(self.salto)
        kdf = PBKDF2HMAC(

            algorithm=hashes.SHA256(),
            length=32,
            salt=self.salto,

            iterations=100,

        )

        key = base64.urlsafe_b64encode(kdf.derive(password))
        return key
            
    def key_write(self, pathZip, key):
        with zipfile.ZipFile(pathZip, 'a') as zip:
            zip.comment = key + bytes(' byMe ', encoding="utf-8") + self.salto
            
        
    def key_load(self, pathZip):
        stri = []
        with zipfile.ZipFile(pathZip, 'a') as zip:
            stri = zip.comment.split(b' byMe ')
            print(stri[0])
            print(stri[1])
            key = stri[0]
            self.salto = stri[1]
        return key
        
    def checkPass(self, pathZip):
        key = base64.urlsafe_b64decode(self.key_load(pathZip))
        salt = self.salto
        mdp = self.getMac()
        mdp = bytes(mdp, encoding="utf-8")
        kdf = PBKDF2HMAC(
            algorithm=hashes.SHA256(),
            length=32,
            salt=salt,
            iterations=100,
        )
        retour = False
        try:
            kdf.verify(mdp, key)
            retour = True
        except:
            retour = False
        return retour
            


    def file_encrypt(self, key, original_file, encrypted_file):
        
        f = Fernet(key)

        with open(original_file, 'rb') as file:
            original = file.read()

        encrypted = f.encrypt(original)

        with open (encrypted_file, 'wb') as file:
            file.write(encrypted)

    def file_decrypt(self, key, encrypted_file, decrypted_file):
        
        f = Fernet(key)

        with open(encrypted_file, 'rb') as file:
            encrypted = file.read()

        decrypted = f.decrypt(encrypted)

        with open(decrypted_file, 'wb') as file:
            file.write(decrypted)
            
    def getMac(self):
        return "".join(re.findall('..', '%012x' % uuid.getnode()))

Use like this:
file : main.py

from second import zipy

#If the argument is empty, the script will make a copy of the directory being executed, otherwise the script will work and output the zip in the place indicated in argument 
dd = zipy("E:/path")
#or dd = zipy("E:/path/") or dd = zipy() if you give arg, give absolute path
#Save the zip and encrypt it. Change second.py to directly give it a password as an argument 
dd.save()
#decrypt zip
dd.decrypt()
Answered By: Emmanuel Rebstock

Here’s a snippet with pyminizip: gets a list of files and zips the whole thing.

import pyminizip
import os


def get_paths_recursively(src_root_path):
    files = []
    if src_root_path is not None:
        for root, directories, filenames in os.walk(src_root_path):
            entries = []
            for filename in filenames:
                full_file_name = os.path.join(root, filename)
                if os.path.isfile(full_file_name) and not filename.startswith('.'):
                    files.append(os.path.join(root, filename))
    return files


def pyminizip_zipper(folder_path, output_path, password):
    paths = get_paths_recursively(folder_path)
    roots = []
    for path in paths:
        roots.append(os.path.dirname(path.replace(os.path.dirname(folder_path), './')))
    pyminizip.compress_multiple(paths, roots, output_path, password, 5)
Answered By: Mickael Tardy
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.