pythonpython-3.xvirtualenvgnupg

gpg.import_keys() is not working in python virtual environment


I'm running this piece of code to encrypt a file using PGP public key.

import gnupg

def pgp_encrypt(pub_file, out_file):

    gpg = gnupg.GPG()

    with open(pub_file, 'rb') as pgp_pub_key:
        public_key_data = pgp_pub_key.read()

    # import_keys_file() is NOT used as the key
    # eventually will come from user-input
    import_result = gpg.import_keys(public_key_data)
    if import_result.count == 0:
        print("Error: No keys imported. Make sure the public key file is correct.")
        exit()

    pgp_key_id = import_result.results[0]['fingerprint']
    plaintext_data = b'This is the TEST data to encrypt'

    encrypted_data = gpg.encrypt(
        plaintext_data,
        recipients=[pgp_key_id],
        always_trust=True
    )

    if encrypted_data.ok:
        print("Data encrypted successfully.")
        print(encrypted_data.data)
        with open(out_file, 'wb') as encrypted_file:
            encrypted_file.write(encrypted_data.data)
    else:
        print("Encryption failed:")
        print(encrypted_data.status)

## Apply
pgp_encrypt('pgp_pubkey.asc', 'pgp_encrypted_file')

So, basically it's reading the public-key file and putting the data in public_key_data, then importing it using gpg.import_keys(public_key_data) before encrypting the file.

print(encrypted_data.data) in my code is not printing the result properly (on the screen, which is another issue to fix) but it's working:

santanu@mgtucrpi5:~/Scripts/gnupg $ python pgp_encrypt.py
Data encrypted successfully.
b'-----BEGIN PGP MESSAGE-----\n\nhQIMA4QM8WwBjfPfAQ/+Jel/JySvuydbuAHDuRT/KwOoFOStYUprQ3TQsj3S3ryJ\nC6bqYD77XviU3fjtcedKxCc0F9Gxw01fb838H0AeACI9Bi4GLuUgS/FJTvrEsX4K\nMniWu4HsConIX+63Ud+RHlVCRziGsa86Uub7GwsaOvYpYhovWzNxc/ObLmoMZaSP\nYmBUHkN+rGGOx4CGGiVS7480Mp2gmd3UyFFbQwV1xO+fz5I+gOcYJSXU0R6SzdXd\nS03sI+8AXLVLmgTARi5ed5V4gr4EIb/bhN18zyUo6gO8vo34GtllFQlRZWL04GRN\n/wg0uudJd26tRxJfCwdcYONKzbNFo8wtLv7dedY+cah+2bTHKFcTWYMGyrhCZZmG\nnZ/GWXnojAz9n9BUNLT/vwQvildfSsuG2qABmk5HUjv0bOH8Ducw6UrbO1pP6hzO\nQcMxGEg8/YQCfI7Zcz1RrIRHWBDlhmG2znDFin2ApyY0N1FmagOJYSZ/ijUkBnT3\nbtIRJ0ISGR7Hjee2G80vKvy0Ozkev2dAhl4Rm3BzoLQV340jEe6dmg8QUPbP0hGU\ni+mlGNMpg50TQVE90ILewhndaBGcBxltS2hVwe+AWj0vhYK3EUqE32Hj7mZxXAWc\nfLTAIXCbsSrZ0Mtc+m6V1IkkwotHaNOea6gqoLMixHbYiwq+F5beu2taYOsespHS\nUQE28ZFF/n6HQ0EUfDuKsd14xUE6UjZvWpfaOor1OedKCife/HkrOOR/VCua1p/T\npROcEBIU2jtazibCiYD1uIy+lwS4w0en8ysFPrLnJuWcFQ==\n=UR1e\n-----END PGP MESSAGE-----\n'

but the moment I run it from virtual environment, I get the following error:

santanu@mgtucrpi5:~/Scripts/gnupg $ source pgpenv/bin/activate
(pgpenv) santanu@mgtucrpi5:~/Scripts/gnupg $ python pgp_encrypt.py
Traceback (most recent call last):
  File "/home/santanu/Scripts/gnupg/pgp_encrypt.py", line 34, in <module>
    pgp_encrypt('pgp_pubkey.asc', 'pgp_encrypted_file')
  File "/home/santanu/Scripts/gnupg/pgp_encrypt.py", line 11, in pgp_encrypt
    if import_result.count == 0:
       ^^^^^^^^^^^^^^^^^^^
AttributeError: 'ImportResult' object has no attribute 'count'. Did you mean: 'counts'?

if I change it to counts (just to try), I get diffrent error, which doesn't look right either:

  File "/home/santanu/Scripts/gnupg/pgpenv/lib/python3.11/site-packages/gnupg/gnupg.py", line 1064, in encrypt
    result = self._encrypt(stream, recipients, **kwargs)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
TypeError: GPGBase._encrypt() got multiple values for argument 'recipients'

How can I fix that?
ref. https://gnupg.readthedocs.io/en/latest/#importing-and-receiving-keys

=======================================

To answer @fqlenos question:

This the way I did the virtual env:

% cd ~/Scripts/gnupg
% python3 -m venv pgpenv
% source pgpenv/bin/activate
% pip install gnupg

I tried with pip install python-gnupg as well but got teh same result. Is there anything I'm missing or doing incorrectly?


Solution

  • How did you create the virtual environment? Did you activate it once it is created?
    Sometimes, we can miss activating the environment and installing the necessary dependencies on it.

    I personally use uv for creating and managing virtual environments:

    $ uv venv
    $ source .venv/bin/activate
    $ (venv) pip install python-gnupg==0.5.4
    

    If you don't use uv, you can always follow this tutorial venv — Creation of virtual environments, you'll get the same result.

    I've just run that snippet of code and it worked perfectly fine within my virtual environment. Make sure you activate and install the correct gnupg python dependency.

    Regarding to the formatter of the result. What you're printing is a byte-formatted string.
    In case you want a more human-readable output you can always do the following:

    if encrypted_data.ok:
        print("Data encrypted successfully.")
        encrypted_str: str = bytes(encrypted_data.data).decode(encoding="utf-8")
        with open(file=out_file, mode="w") as encrypted_file:
            encrypted_file.write(encrypted_str)
        print(encrypted_str)
    

    I've just casted the encrypted_data.data to bytes() and decoded it in UTF-8.