From bea899d1efc0c572f25875faaa4e25d6a7b5e687 Mon Sep 17 00:00:00 2001 From: Roman Zeyde Date: Wed, 25 Apr 2018 11:09:58 +0300 Subject: [PATCH] gpg: allow symmetric encryption with a passphrase --- libagent/device/ui.py | 8 ++++---- libagent/gpg/agent.py | 22 ++++++++++++++++++++-- libagent/gpg/keyring.py | 4 ++-- 3 files changed, 26 insertions(+), 8 deletions(-) diff --git a/libagent/device/ui.py b/libagent/device/ui.py index cdeaa91..1b9b985 100644 --- a/libagent/device/ui.py +++ b/libagent/device/ui.py @@ -24,7 +24,7 @@ class UI(object): self.options_getter = create_default_options_getter() self.device_name = device_type.__name__ - def get_pin(self): + def get_pin(self, name=None): """Ask the user for (scrambled) PIN.""" description = ( 'Use the numeric keypad to describe number positions.\n' @@ -33,16 +33,16 @@ class UI(object): ' 4 5 6\n' ' 1 2 3') return interact( - title='{} PIN'.format(self.device_name), + title='{} PIN'.format(name or self.device_name), prompt='PIN:', description=description, binary=self.pin_entry_binary, options=self.options_getter()) - def get_passphrase(self): + def get_passphrase(self, name=None): """Ask the user for passphrase.""" return interact( - title='{} passphrase'.format(self.device_name), + title='{} passphrase'.format(name or self.device_name), prompt='Passphrase:', description=None, binary=self.passphrase_entry_binary, diff --git a/libagent/gpg/agent.py b/libagent/gpg/agent.py index 0079fe4..516be83 100644 --- a/libagent/gpg/agent.py +++ b/libagent/gpg/agent.py @@ -102,6 +102,7 @@ class Handler(object): b'HAVEKEY': lambda _, args: self.have_key(*args), b'KEYINFO': _key_info, b'SCD': self.handle_scd, + b'GET_PASSPHRASE': self.handle_get_passphrase, } def reset(self): @@ -115,9 +116,26 @@ class Handler(object): self.options.append(opt) log.debug('options: %s', self.options) - def handle_getinfo(self, conn, _args): + def handle_get_passphrase(self, conn, args): + passphrase = self.client.device.ui.get_passphrase('Symmetric encryption') + result = b'D ' + util.assuan_serialize(passphrase.encode('ascii')) + keyring.sendline(conn, result, confidential=True) + + def handle_getinfo(self, conn, args): """Handle some of the GETINFO messages.""" - keyring.sendline(conn, b'D ' + self.version) + result = None + if args[0] == b'version': + result = self.version + elif args[0] == b's2k_count': + # Use highest number of S2K iterations. + # https://www.gnupg.org/documentation/manuals/gnupg/OpenPGP-Options.html + # https://tools.ietf.org/html/rfc4880#section-3.7.1.3 + result = '{}'.format(64 << 20).encode('ascii') + else: + log.warning('Unknown GETINFO command: %s', args) + + if result: + keyring.sendline(conn, b'D ' + result) def handle_scd(self, conn, args): """No support for smart-card device protocol.""" diff --git a/libagent/gpg/keyring.py b/libagent/gpg/keyring.py index 85adc55..e001ffb 100644 --- a/libagent/gpg/keyring.py +++ b/libagent/gpg/keyring.py @@ -48,9 +48,9 @@ def communicate(sock, msg): return recvline(sock) -def sendline(sock, msg): +def sendline(sock, msg, confidential=False): """Send a binary message, followed by EOL.""" - log.debug('<- %r', msg) + log.debug('<- %r', ('' if confidential else msg)) sock.sendall(msg + b'\n')