Make your python script safety?

Make your python script SAFETY

Background

We know when we run Python script we can get the .pyc files. But there are some tools that can decompile .pyc files to .py files. It is not a good behavior but in China, a lot of people are using it.

How to make your python script safety ?

I want to invent a new kind of file pye. pye is safety than .pyc file. We can use AES to encrypt the .pyc file to .pye file. And when we run .pye file, we can use AES to decrypt the .pye file to .pyc file. The AES key should be store safety. We can use pye to make your python script safety.

Here is the code to encrypt pyc to pye:


import os
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad
from Crypto.Random import get_random_bytes

# generate a random key
key = get_random_bytes(32)  # AES-256

# encrypt pyc to pye
def encrypt_pyc_to_pye(input_file, output_file, key):
    cipher = AES.new(key, AES.MODE_CBC)
    with open(input_file, 'rb') as f:
        data = f.read()
    encrypted_data = cipher.encrypt(pad(data, AES.block_size))
    with open(output_file, 'wb') as f:
        f.write(cipher.iv)
        f.write(encrypted_data)

# example
encrypt_pyc_to_pye('example.pyc', 'example.pye', key)

# decrypt pye to pyc
def decrypt_pye_to_pyc(input_file, output_file, key):
    with open(input_file, 'rb') as f:
        iv = f.read(AES.block_size)
        encrypted_data = f.read()
    cipher = AES.new(key, AES.MODE_CBC, iv)
    decrypted_data = unpad(cipher.decrypt(encrypted_data), AES.block_size)
    with open(output_file, 'wb') as f:
        f.write(decrypted_data)

# example
decrypt_pye_to_pyc('example.pye', 'example.pyc', key)

# run example.py
os.system('python -m example')

Let’s make the test. First install uncompyle6.

pip install uncompyle6

Write the example.py: (Anything is okay!)

print("Hello World!")

Get the .pyc file:

import py_compile
py_compile.compile('example.py', 'example.pyc')

Let’s uncrypted .pyc file, we can get the source code. (You can use uncompyle6 to decompile .pyc file or you can use some websites like pydecompile)

If we use .pyc, we can get the source code. But what about .pye? NOTHING!

Now we can make sure .pye is safe. We can make it more safe by using asymmetric encryption. But it may cost some times.

Here is the code to encrypt pyc to pye using asymmetric encryption:

import os
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad
from Crypto.Random import get_random_bytes
from Crypto.Hash import HMAC, SHA256

key = get_random_bytes(32)  # AES-256

hmac_key = get_random_bytes(32)  # HMAC-SHA256

# write keys to file
def write_keys_to_file(key, hmac_key):
    with open('.keys', 'wb') as f:
        f.write(key)
        f.write(hmac_key)

write_keys_to_file(key, hmac_key)

# pyc to pye
def encrypt_pyc_to_pye(input_file, output_file, key, hmac_key):
    cipher = AES.new(key, AES.MODE_CBC)
    with open(input_file, 'rb') as f:
        data = f.read()
    encrypted_data = cipher.encrypt(pad(data, AES.block_size))

    # calculate hmac
    hmac = HMAC.new(hmac_key, digestmod=SHA256)
    hmac.update(encrypted_data)
    hmac_value = hmac.digest()

    with open(output_file, 'wb') as f:
        f.write(cipher.iv)
        f.write(encrypted_data)
        f.write(hmac_value)

encrypt_pyc_to_pye('example.pyc', 'example.pye', key, hmac_key)

Decrypt pye to pyc:


import os
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad
from Crypto.Hash import HMAC, SHA256

# read keys from file
def read_keys_from_file():
    with open('.keys', 'rb') as f:
        key = f.read(32)
        hmac_key = f.read(32)
    return key, hmac_key

# decrypt pye to pyc
def decrypt_pye_to_pyc(input_file, output_file, key, hmac_key):
    with open(input_file, 'rb') as f:
        iv = f.read(AES.block_size)  # read iv
        encrypted_data = f.read(-32)  # read encrypted data
        hmac_value = f.read(32)  # read hmac

    hmac = HMAC.new(hmac_key, digestmod=SHA256)
    hmac.update(encrypted_data)
    if not hmac.verify(hmac_value):
        raise ValueError("HMAC verification failed")

    cipher = AES.new(key, AES.MODE_CBC, iv=iv)
    decrypted_data = unpad(cipher.decrypt(encrypted_data), AES.block_size)

    with open(output_file, 'wb') as f:
        f.write(decrypted_data)

key, hmac_key = read_keys_from_file()
decrypt_pye_to_pyc('example.pye', 'example.pyc', key, hmac_key)

This kind of way is more safe than .pyc file. But it may cost some times.

Conclusion

We can make our python script safety by using pye. It is more safe than .pyc file. But it may cost some times. If you do not need high safety, AES is enough. But if you need high safety, you can use asymmetric encryption such as RSA.

End

This is my second discuss. I am not good at English. I am sorry for that. Say what you want to say !! (Bug report & fix, Better soultion, Idea, etc.)

And how are people supposed to run your code unless you give them the decryption key and therefore the means to decompile your code again?

Thank you. That’s a good question. We may only give the key to some people. Or we can change the key regularly (like two month?)

I realize this is a difficult problems, but it must be solutions. I expected…

In this case I will simply connect a tool to pull the bytes code out of the python processes address space. All your efforts are easy to bypass.

Once you give the code to a bad actor they can turn it back into some form of source code, given enough time and resources.

The best you can hope to do is make it hard to turn back in to something the bad actor can then modify. In which case python is not a good starting point.

Then why not just put your code in an encrypted zip file and give the decryption key to the people you want to be able to run it? Or just not give the code to people who shouldn’t have it in the first place?

I find articles. < 手把手教你定制python解释器,保护你的python源代码 - 『编程语言区』 - 吾爱破解 - LCG - LSG |安卓破解|病毒分析|www.52pojie.cn> < Python加密器:修改CPython解释器来保护Python代码 - 文章 - 开发者社区 - 火山引擎 (volcengine.com)>

Their languages are Chinese. Solution of the first link:
The content mainly introduces a method to protect Python source code by customizing the Python interpreter and using encryption techniques to prevent the code from being easily decompiled. The specific steps include modifying the opcode definitions in opcode.h , compiling a customized Python interpreter, and compiling .py files into encrypted .pye files. Additionally, it explains how to make the customized interpreter recognize and run .pye files, thus achieving better code protection.

The sencond link : Author find a kind of Python encrypter and tell us how to install it.

The key here that is, exactly what I was saying, it prevents easily decompiling, so you just have to want to get the source code and its yours.

What you want is code obfuscation. There exist several projects to do that (search “python obfuscation”). Some use encryption keys, if you’re into that.

Personally, I would say that if you don’t want your code decompiled, you shouldn’t distribute your code.

I think this post should probably be moved to the general discussion category, as I don’t think this is at Ideas stage.

Given the normal Python interpreter there is no way to ensure that someone can (1) run your code (app or library) and (2) not be able to decompile it into byte code, and from there into some source code representation. Building a special interpreter is not a solution at all, since this will at runtime still need to convert everything into regular Python byte-code.

Obfuscation (of the original script) can make it more challenging to understand the underlying code, but not terribly more so – since you can run the app in a debugger…

So, I think the only way to not reveal the underlying code is to not distribute it at all. This implies that the only way to make it then usable by others is by hosting it as a web service – which only reveals the GUI (and/or API). Trying to solve these kind of security concerns at the level of Python code distributions or the Python interpreter is not going to work.

1 Like

Hi everyone,

Thank you for your insightful comments and suggestions. We can use pyinstaller. To my example, is very easy:

pyinstaller --onefile --name=your_name example.py

A PyInstaller application is just a glorified zip-like archive of .pyc files appended to an executable and is no more built to hide source code that Python’s bytecode compiler. There are several PyInstaller deconstructors available which will extract the .pyc files to feed into a .pyc.py decompiler.

1 Like

PyInstaller ships this tool to get inside the archive in the single file .exe, pyi-archive_viewer.