Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unable to import private key with passpharse #284

Open
pajuscz opened this issue May 4, 2022 · 4 comments
Open

Unable to import private key with passpharse #284

pajuscz opened this issue May 4, 2022 · 4 comments

Comments

@pajuscz
Copy link

pajuscz commented May 4, 2022

I came across this while looking into this closed issue: #194

I wasn't able to import private key with passpharse using the same method. What happens is that public key is imported, but not the secret key - I cannot decrypt data after I do the import.

While looking into the code I don't think it is possible to import a key using passpharse, because the passpharse is set to False by default.

The _handle_io:
def _handle_io(self, args, file, result, passphrase=False, binary=False):

called from import_keys(self, key_data) is called in this fashion:
self._handle_io(['--import'], data, result, binary=True) I don't see a way to pass passphase there.

When I 'hard-code' the passphasee into the self._handle_io(['--import'], data, result, passphrase='secret', binary=True)
It works as expected. I think there should be a posibility to pass passpharse as an argument into GPG.import_keys()

@pajuscz
Copy link
Author

pajuscz commented May 4, 2022

The key I am trying to import is:

-----BEGIN PGP PRIVATE KEY BLOCK-----

lQdGBGJy/wcBEAC6IvcYBmhTnFZNi+qYMTwPf2pixNx6IWUQZaGlbEBStuSucWZ2
MuAVDeL1+ahOUanResjfLgk0ivZ5ZykfDR4wrW9gqoahLFFu2Xb2S6eyIaba2Phm
Z+0xOLOdtambrxZDuN+/NCZoXE2EpZcVyeR4tiN1GrjNqF7jMwYBL8tjPGc1gLu+

When I do gpg --import import.key I am prompted for passpharse,

When I use GPG.import_keys() I don't know how to pass the passpharse and as a result I am getting:


'1' (4560127240) = {str} 'Invalid Certificate'
'0' (4563316368) = {str} 'No specific reason given'
'3' (4561059072) = {str} 'Certificate Chain too long'
'2' (4559698000) = {str} 'Issuer Certificate missing'
'4' (4561059112) = {str} 'Error storing certificate'

'17' (4570749568) = {str} 'Contains private key'
'16' (4570747448) = {str} 'Contains private key'
'1' (4560127240) = {str} 'Entirely new key'
'0' (4563316368) = {str} 'Not actually changed'
'2' (4559698000) = {str} 'New user IDs'
'4' (4561059112) = {str} 'New signatures'
'8' (4563315368) = {str} 'New subkeys'

u'gpg: no valid OpenPGP data found.
[GNUPG:] NODATA 1
gpg: Total number processed: 0
[GNUPG:] IMPORT_RES 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
'

@pajuscz
Copy link
Author

pajuscz commented May 4, 2022

The actual stacktrace with exception is here:

Traceback (most recent call last):
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/threading.py", line 801, in __bootstrap_inner
    self.run()
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/threading.py", line 754, in run
    self.__target(*self.__args, **self.__kwargs)
  File "lib/python2.7/site-packages/pretty_bad_protocol/_meta.py", line 670, in _read_response
    result._handle_status(keyword, value)
  File "/lib/python2.7/site-packages/pretty_bad_protocol/_parsers.py", line 1304, in _handle_status
    raise ValueError("Unknown status message: %r" % key)
ValueError: Unknown status message: u'USERID_HINT'
Exception in thread Thread-47:
Traceback (most recent call last):
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/threading.py", line 801, in __bootstrap_inner
    self.run()
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/threading.py", line 754, in run
    self.__target(*self.__args, **self.__kwargs)
  File "/lib/python2.7/site-packages/pretty_bad_protocol/_meta.py", line 670, in _read_response
    result._handle_status(keyword, value)
  File "lib/python2.7/site-packages/pretty_bad_protocol/_parsers.py", line 1304, in _handle_status
    raise ValueError("Unknown status message: %r" % key)
ValueError: Unknown status message: u'USERID_HINT'

@pajuscz
Copy link
Author

pajuscz commented May 4, 2022

I am using options=['--yes', '--pinentry-mode loopback'] when initializing the GPG object if that helps.

If I don't use it - there is no error, nor exception but the secret key is not imported - only the public key.

@erickeniuk
Copy link

erickeniuk commented Jun 1, 2023

Hi @pajuscz , I ran into this issue as well. You can simply pass passphrase to the _handle_io() as it is an already an available parameter when self._handle_io() is called within decrypt_files()

Changes made within gnupg.py:

def import_keys(self, key_data, passphrase=False):

and

self._handle_io(['--import'], data, result, passphrase, binary=True)

I tested these changes on my machine and I had a few unknown statuses which I had to patch as well within _parsers.py but after that I had no issues importing keys with passphrases. The other solution would be likely to import keys with no passphrase.

    def import_keys(self, key_data, passphrase=False):
    """
    Import the key_data into our keyring.

    >>> import shutil
    >>> shutil.rmtree("doctests")
    >>> gpg = gnupg.GPG(homedir="doctests")
    >>> inpt = gpg.gen_key_input()
    >>> key1 = gpg.gen_key(inpt)
    >>> print1 = str(key1.fingerprint)
    >>> pubkey1 = gpg.export_keys(print1)
    >>> seckey1 = gpg.export_keys(print1,secret=True)
    >>> key2 = gpg.gen_key(inpt)
    >>> print2 = key2.fingerprint
    >>> seckeys = gpg.list_keys(secret=True)
    >>> pubkeys = gpg.list_keys()
    >>> assert print1 in seckeys.fingerprints
    >>> assert print1 in pubkeys.fingerprints
    >>> str(gpg.delete_keys(print1))
    'Must delete secret key first'
    >>> str(gpg.delete_keys(print1,secret=True))
    'ok'
    >>> str(gpg.delete_keys(print1))
    'ok'
    >>> pubkeys = gpg.list_keys()
    >>> assert not print1 in pubkeys.fingerprints
    >>> result = gpg.import_keys(pubkey1)
    >>> pubkeys = gpg.list_keys()
    >>> seckeys = gpg.list_keys(secret=True)
    >>> assert not print1 in seckeys.fingerprints
    >>> assert print1 in pubkeys.fingerprints
    >>> result = gpg.import_keys(seckey1)
    >>> assert result
    >>> seckeys = gpg.list_keys(secret=True)
    >>> assert print1 in seckeys.fingerprints
    """
    ## xxx need way to validate that key_data is actually a valid GPG key
    ##     it might be possible to use --list-packets and parse the output

    result = self._result_map['import'](self)
    log.info('Importing: %r', key_data[:256])
    data = _make_binary_stream(key_data, self._encoding)
    self._handle_io(['--import'], data, result, passphrase, binary=True)
    data.close()
    return result

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants