ENC is a free standalone Python code base encryption utility. This utility is designed to create a single runnable unit out of multiple Python modules and is intended to help anyone looking to create non-readable Python applications.
The easiest way to get the code is simply to clone this repository to your local machine!
- Python 2.7.x
- Pip
- astunparse 1.4+
- cement 2.10+
- pycrypto 2.6+
Once you have acquired the code you only need to make sure you have the required modules installed. The can be easily accomplished using pip. Simply run pip install -r requirements.txt
with the included requirements.txt file and the required files will be downloaded over the Internet from the Python package index.
ENC has two main parts. The first part enc.py
is the encryption tool and does the work of actually creating and outputting an encrypted unit. The second part run.py
is tool that executes the encrypted unit.
enc.py
can be run on one or more Python modules to create a single, encrypted, runnable unit. ENC is designed to protect applications not libraries/modules for import (though this functionality will hopefully be added in the future). This roughly translates to "you need to have an entry point in your program." This is necessary because ENC will prompt you for a password and then begin running your encrypted unit. enc.py
has various options for specifying how your Python code will be stored in an encrypted unit. For example, the output unit can either be stored as a native Python AST object or as raw Python code (both encrypted) and can be compressed for a more compact representation on disk. ENC makes extensive use of Python Abstract Syntax Trees to intelligently re-write portions of your program that would otherwise inhibit you from joining together multiple Python scripts. enc.py
only encrypts the files you tell it to and does not effect any imports in your program. If you for example, used the time module in a program (import time
), enc.py
will not encrypt time.py
without explicitly being told to do so.
run.py
can decrypt and run any encrypted unit generated by enc.py
. Simply specify the encrypted unit you wish to run, enter your password when prompted and run.py
will decrypt your file and begin executing your program. run.py
can execute programs that use command line parameters, this was tested with both argparse
and directly through sys.argv
.
ENC in its current form is intended to be used to make Python code bases purely executable (and technically writable). Specifically it is not currently setup to trigger code execution from a remote location, or to protect scripts that will become a daemon or service. The most likely use case for ENC is multi-tenant environment that a user would probably SSH into. ENC is extremely secure when files are at rest. It uses AES encryption and IVs generated using a cryptographic random number generator.
However this changes when a program protected with ENC is executed. When the encrypted unit is run the encrypted source is loaded into a buffer in memory and then decrypted. If someone else has root access to that machine they absolutely can dump physical memory and read the contents of the decrypted buffer. However this is easier in theory than practice. Luckily code is not stored as clear text Python in the encrypted unit. Instead the contents of the file is a serialized Python abstract syntax tree which is then loaded back into an object at which point the original buffer is immediately garbarge collected. However your files are still safe if your attacker does not have root access as the OS protects any memory owned by the process from being accessed by any user that did not spawn the process. I added the ability to embed a Canary token into the runner agent. This way you'll be notified when anyone tries to execute your program regardless of if they actually have the password or not.
So what does that mean? As always if your attacker has root access you have already been defeated. Programs protected with ENC are no different.
That said, can we do better? Of course! In the next major version of ENC I plan to have the utility actually build a custom python interpreter with randomly generated opcodes. This means that a .pyc
file generated using the utility will be virtually immune to any types of decompilation or reversing tools. This plus encryption yields a solution that is pretty darn (though not perfectly) secure!
ENC is extremely generic and can be used in many ways. Most often ENC is run as a standalone or inside a Jenkins build process. Because ENC has a CLI it can be easily adapted for many projects.
To see ENC in action simply run the utility over some Python files as follows:
python enc.py -e file_with_entry_point.py -s file_with_entry_point.py another_required_module.py -p admin -o unit.enc -c
This will create a single encrypted unit called unit.enc
comprised of files file_with_entry_point.py
and another_required_module.py
with the password admin
and stored as a compressed Python AST object.
This will output a file called 'unit.enc' which can then be easily run with run.py
as follows:
python run.py unit.enc
Any required command line parameters can be passed as additional arguments to run.py
like so:
python run.py unit.enc --additional-parameter xxx
Try running ENC on the files in the examples directory:
- entry.py - the file containing the program entry point
- aux.py - an additional file required by entry.py
- another.py - another file required by entry.py
Before trying ENC, run the example as follows:
python entry.py
and
python entry.py helloWorld
to familiarize yourself with the output of the program. Now try the same thing using ENC.
This can be done using the following commands:
python $ENC_HOME/enc.py -e entry.py -s entry.py aux.py another.py -o test.enc -p admin -c
python $ENC_HOME/run.py test.enc
or
python $ENC_HOME/run.py test.enc helloWorld
enter admin
and you will see the same output as before!
Note that there is no way to return an encrypted unit to its decrypted state if you forget the password, be sure to keep it safe.
To see the built in help menu simply run:
python enc.py -h
enc.py
Flag | Long Flag | Effect | Required |
---|---|---|---|
-h | --help | Show help message and exit | N |
--quiet | Suppress all output | N | |
-e ENTRY | --entry ENTRY | Specify file as application entry point | Y |
-s [SOURCE [SOURCE ...]] | --source [SOURCE [SOURCE ...]] | Space separated list of source files to be encrypted | Y |
-p PASSWORD | --password PASSWORD | Password/secret used to encrypt source files | Y |
-o OUTPUT | --output OUTPUT | Specify output path and filename | N |
-t {a,r} | --type {a,r} | Store as an AST object (default, for compatibility) or store as raw code (file size) | N |
-c | --compress | Compress output format for reduced file size (zlib) | N |
-d | --debugOutput | Prints the approximate source code that will be placed into the runnable unit (before encryption) | N |
-l LOAD | --load LOAD | Load in a single file to be encrypted. Mainly used after correcting issues while debugging | N |
Note: --debug
and --debugOutput
are not equivalent. The first is enc.py
level debugging, and the second is a preview of what enc.py
will output for a single runnable unit. This is extremely useful if you are having problems encrypting your program. For example you can simply run:
python enc.py -e hello.py -s hello.py -p admin -d > run_this.py
This will dump the joined source to a file in clear text. You can then locally run:
python run_this.py
to figure out what is going wrong. After correcting the problem you should use the -l
or --load
flag to "re-submit" your file for encryption. This might look like:
python enc.py -l run_this.py -p admin -o anon.enc
Now anon.enc
can be run in the normal way. This feature is mostly useful in the event that the user finds an edge case that the ENC utility is not properly setup to handle (though these features should be implemented as they are discovered...and don't worry tests are coming).
Anyone is welcome to use ENC for their own projects provided that you adhere to the GPL 3.0 license included with the software! Its not required but I would also appreciate it if you would mention this project in your source!
ENC is completely open source and I welcome anyone who would like to contribute to the project. If you're interested in contributing please contact me and/or submit a pull request! I plan to make a number of updates to the code myself, including performance increases, style refactoring and some new features but I can't do it all myself!