Search code examples
pythonimportgnupgpgp

PGP/GPG Signed Python code


I'd like to (PGP/GPG) sign python code. Yes, I have read this and many other sites that talk about protecting and obfuscating python code - this all is not what I want. I DON'T want to obfuscate code. I want customers and users to see the code, they could modify code, copy it and make derivative work, I'd like to have the software under the GPLv3. But I want to have plugins that are "signed", so they can be kind of trusted during execution.

Is this possible in Python? Can I import a library after checking its gpg signing? What would be easy: check the gpg signing of a file, and then load it via import, else raise an exception. But this only would be possible for single-file-imports, not directory python modules.

It is clear that, if the customer changes the GPG key in the program, or deletes some lines himself in the checking algorithm, all is gone - but this is not the problem. He could do anything he wants - but this would be silly. What he wants is trustworthiness. I want to let him add a third party plugin by copying it into a "plugins" directory, and have the program check the plugin for "trustworthiness" - and then import it. (So he could run plugins that are not signed, but with his own risk.)


Solution

  • Python's import mechanism already provide all the tools necessary to achieve what you want. You can install different kinds of import hooks in order to support what you want.

    In particular you'll probably find convenient to install a meta path hook that searches for "signed modules" and returns a Loader that is able to perform the imports from this signed format.

    A very simple and convenient format for your signed plug-ins would be a zip archive containing:

    1. The code of the plug-in in the form of modules/packages
    2. A PGP signature of the above code

    In this way:

    • Your loader should unpack the zip, and check the signature. If it matches then you can safely load the plug-in, if it doesn't match you should ask the user to trust the plug-in (or not and abort)
    • If the user wants to modify the plug-in it can simply unpack the zip archive and modify it as he wishes.
    • Imports from zip archives are already implemented in the zipimport module. This means that you don't have to rewrite a loader from scratch.

    Actually if you want to reduce the code for the hooks to the minimum you'd simply need to verify the signature and then add the path to the zip archive into sys.path, since python already handles imports from zip archive even without explicitly using zipimport.

    Using this design you just have to install these hooks and then you can import the plug-in as if they were normal modules and the verification etc. will be done automatically.