diff --git a/gnupg/_meta.py b/gnupg/_meta.py index 4f9f77b..530064d 100644 --- a/gnupg/_meta.py +++ b/gnupg/_meta.py @@ -582,3 +582,160 @@ class GPGBase(object): writer = None self._collect_output(proc, result, writer, proc.stdin) return result + + def _encrypt(self, data, recipients, + default_key=None, + passphrase=None, + armor=True, + encrypt=True, + symmetric=False, + always_trust=True, + output=None, + cipher_algo='AES256', + digest_algo='SHA512', + compress_algo='ZLIB'): + """Encrypt the message read from the file-like object ``data``. + + :param str data: The file or bytestream to encrypt. + + :param str recipients: The recipients to encrypt to. Recipients must + be specified keyID/fingerprint. Care should be taken in Python2.x + to make sure that the given fingerprint is in fact a string and + not a unicode object. + + :param str default_key: The keyID/fingerprint of the key to use for + signing. If given, ``data`` will be encrypted and signed. + + :param str passphrase: If given, and ``default_key`` is also given, + use this passphrase to unlock the secret portion of the + ``default_key`` to sign the encrypted ``data``. Otherwise, if + ``default_key`` is not given, but ``symmetric=True``, then use + this passphrase as the passphrase for symmetric + encryption. Signing and symmetric encryption should *not* be + combined when sending the ``data`` to other recipients, else the + passphrase to the secret key would be shared with them. + + :param bool armor: If True, ascii armor the output; otherwise, the + output will be in binary format. (Default: True) + + :param bool encrypt: If True, encrypt the ``data`` using the + ``recipients`` public keys. (Default: True) + + :param bool symmetric: If True, encrypt the ``data`` to ``recipients`` + using a symmetric key. See the ``passphrase`` parameter. Symmetric + encryption and public key encryption can be used simultaneously, + and will result in a ciphertext which is decryptable with either + the symmetric ``passphrase`` or one of the corresponding private + keys. + + :param bool always_trust: If True, ignore trust warnings on recipient + keys. If False, display trust warnings. (default: True) + + :param str output: The output file to write to. If not specified, the + encrypted output is returned, and thus should be stored as an + object in Python. For example: + + >>> import shutil + >>> import gnupg + >>> if os.path.exists("doctests"): + ... shutil.rmtree("doctests") + >>> gpg = gnupg.GPG(homedir="doctests") + >>> key_settings = gpg.gen_key_input(key_type='RSA', + ... key_length=1024, + ... key_usage='ESCA', + ... passphrase='foo') + >>> key = gpg.gen_key(key_settings) + >>> message = "The crow flies at midnight." + >>> encrypted = str(gpg.encrypt(message, key.printprint)) + >>> assert encrypted != message + >>> assert not encrypted.isspace() + >>> decrypted = str(gpg.decrypt(encrypted)) + >>> assert not decrypted.isspace() + >>> decrypted + 'The crow flies at midnight.' + + :param str cipher_algo: The cipher algorithm to use. To see available + algorithms with your version of GnuPG, do: + ``$ gpg --with-colons --list-config ciphername``. + The default ``cipher_algo``, if unspecified, is ``'AES256'``. + + :param str digest_algo: The hash digest to use. Again, to see which + hashes your GnuPG is capable of using, do: + ``$ gpg --with-colons --list-config digestname``. + The default, if unspecified, is ``'SHA512'``. + + :param str compress_algo: The compression algorithm to use. Can be one + of ``'ZLIB'``, ``'BZIP2'``, ``'ZIP'``, or ``'Uncompressed'``. + """ + args = [] + + if output: + if getattr(output, 'fileno', None) is not None: + ## avoid overwrite confirmation message + if getattr(output, 'name', None) is None: + if os.path.exists(output): + os.remove(output) + args.append('--output %s' % output) + else: + if os.path.exists(output.name): + os.remove(output.name) + args.append('--output %s' % output.name) + + if armor: args.append('--armor') + if always_trust: args.append('--always-trust') + if cipher_algo: args.append('--cipher-algo %s' % cipher_algo) + if compress_algo: args.append('--compress-algo %s' % compress_algo) + + if default_key: + args.append('--sign') + args.append('--default-key %s' % default_key) + if digest_algo: + args.append('--digest-algo %s' % digest_algo) + + ## both can be used at the same time for an encrypted file which + ## is decryptable with a passphrase or secretkey. + if symmetric: args.append('--symmetric') + if encrypt: args.append('--encrypt') + + if len(recipients) >= 1: + log.debug("GPG.encrypt() called for recipients '%s' with type '%s'" + % (recipients, type(recipients))) + + if isinstance(recipients, (list, tuple)): + for recp in recipients: + if not _util._py3k: + if isinstance(recp, unicode): + try: + assert _parsers._is_hex(str(recp)) + except AssertionError: + log.info("Can't accept recipient string: %s" + % recp) + else: + args.append('--recipient %s' % str(recp)) + continue + ## will give unicode in 2.x as '\uXXXX\uXXXX' + args.append('--recipient %r' % recp) + continue + if isinstance(recp, str): + args.append('--recipient %s' % recp) + + elif (not _util._py3k) and isinstance(recp, basestring): + for recp in recipients.split('\x20'): + args.append('--recipient %s' % recp) + + elif _util._py3k and isinstance(recp, str): + for recp in recipients.split(' '): + args.append('--recipient %s' % recp) + ## ...and now that we've proven py3k is better... + + else: + log.debug("Don't know what to do with recipients: '%s'" + % recipients) + + result = self._result_map['crypt'](self) + log.debug("Got data '%s' with type '%s'." + % (data, type(data))) + self._handle_io(args, data, result, + passphrase=passphrase, binary=True) + log.debug('GPG.encrypt_file(): Result: %r', result.data) + return result diff --git a/gnupg/gnupg.py b/gnupg/gnupg.py index d0b3a22..929a9ce 100644 --- a/gnupg/gnupg.py +++ b/gnupg/gnupg.py @@ -831,135 +831,82 @@ generate keys. Please see return out - def encrypt_file(self, filename, recipients, - default_key=None, - passphrase=None, - armor=True, - encrypt=True, - symmetric=False, - always_trust=True, - output=None, - cipher_algo='AES256', - digest_algo='SHA512', - compress_algo='ZLIB'): - """Encrypt the message read from the file-like object ``filename``. - - :param str filename: The file or bytestream to encrypt. - :param str recipients: The recipients to encrypt to. Recipients must - be specified keyID/fingerprint. Care should be - taken in Python2.x to make sure that the given - fingerprint is in fact a string and not a - unicode object. - :param str default_key: The keyID/fingerprint of the key to use for - signing. If given, ``filename`` will be - encrypted and signed. - :param bool always_trust: If True, ignore trust warnings on recipient - keys. If False, display trust warnings. - (default: True) - :param str passphrase: If True, use this passphrase to unlock the - secret portion of the ``default_key`` for - signing. - :param bool armor: If True, ascii armor the output; otherwise, the - output will be in binary format. (default: True) - :param str output: The output file to write to. If not specified, the - encrypted output is returned, and thus should be - stored as an object in Python. For example: - """ - args = [] - - if output: - if getattr(output, 'fileno', None) is not None: - ## avoid overwrite confirmation message - if getattr(output, 'name', None) is None: - if os.path.exists(output): - os.remove(output) - args.append('--output %s' % output) - else: - if os.path.exists(output.name): - os.remove(output.name) - args.append('--output %s' % output.name) - - if armor: args.append('--armor') - if always_trust: args.append('--always-trust') - if cipher_algo: args.append('--cipher-algo %s' % cipher_algo) - if compress_algo: args.append('--compress-algo %s' % compress_algo) - - if default_key: - args.append('--sign') - args.append('--default-key %s' % default_key) - if digest_algo: - args.append('--digest-algo %s' % digest_algo) - - ## both can be used at the same time for an encrypted file which - ## is decryptable with a passphrase or secretkey. - if symmetric: args.append('--symmetric') - if encrypt: args.append('--encrypt') - - if len(recipients) >= 1: - log.debug("GPG.encrypt() called for recipients '%s' with type '%s'" - % (recipients, type(recipients))) - - if isinstance(recipients, (list, tuple)): - for recp in recipients: - if not _util._py3k: - if isinstance(recp, unicode): - try: - assert _parsers._is_hex(str(recp)) - except AssertionError: - log.info("Can't accept recipient string: %s" - % recp) - else: - args.append('--recipient %s' % str(recp)) - continue - ## will give unicode in 2.x as '\uXXXX\uXXXX' - args.append('--recipient %r' % recp) - continue - if isinstance(recp, str): - args.append('--recipient %s' % recp) - - elif (not _util._py3k) and isinstance(recp, basestring): - for recp in recipients.split('\x20'): - args.append('--recipient %s' % recp) - - elif _util._py3k and isinstance(recp, str): - for recp in recipients.split(' '): - args.append('--recipient %s' % recp) - ## ...and now that we've proven py3k is better... - - else: - log.debug("Don't know what to do with recipients: '%s'" - % recipients) - - result = self._result_map['crypt'](self) - log.debug("Got filename '%s' with type '%s'." - % (filename, type(filename))) - self._handle_io(args, filename, result, - passphrase=passphrase, binary=True) - log.debug('GPG.encrypt_file(): Result: %r', result.data) - return result - def encrypt(self, data, *recipients, **kwargs): """Encrypt the message contained in ``data`` to ``recipients``. + :param str data: The file or bytestream to encrypt. + + :param str recipients: The recipients to encrypt to. Recipients must + be specified keyID/fingerprint. Care should be taken in Python2.x + to make sure that the given fingerprint is in fact a string and + not a unicode object. + + :param str default_key: The keyID/fingerprint of the key to use for + signing. If given, ``data`` will be encrypted and signed. + + :param str passphrase: If given, and ``default_key`` is also given, + use this passphrase to unlock the secret portion of the + ``default_key`` to sign the encrypted ``data``. Otherwise, if + ``default_key`` is not given, but ``symmetric=True``, then use + this passphrase as the passphrase for symmetric + encryption. Signing and symmetric encryption should *not* be + combined when sending the ``data`` to other recipients, else the + passphrase to the secret key would be shared with them. + + :param bool armor: If True, ascii armor the output; otherwise, the + output will be in binary format. (Default: True) + + :param bool encrypt: If True, encrypt the ``data`` using the + ``recipients`` public keys. (Default: True) + + :param bool symmetric: If True, encrypt the ``data`` to ``recipients`` + using a symmetric key. See the ``passphrase`` parameter. Symmetric + encryption and public key encryption can be used simultaneously, + and will result in a ciphertext which is decryptable with either + the symmetric ``passphrase`` or one of the corresponding private + keys. + + :param bool always_trust: If True, ignore trust warnings on recipient + keys. If False, display trust warnings. (default: True) + + :param str output: The output file to write to. If not specified, the + encrypted output is returned, and thus should be stored as an + object in Python. For example: + >>> import shutil + >>> import gnupg >>> if os.path.exists("doctests"): ... shutil.rmtree("doctests") - >>> gpg = GPG(homedir="doctests") + >>> gpg = gnupg.GPG(homedir="doctests") >>> key_settings = gpg.gen_key_input(key_type='RSA', ... key_length=1024, ... key_usage='ESCA', ... passphrase='foo') >>> key = gpg.gen_key(key_settings) - >>> encrypted = gpg.encrypt("sekrit", key.printprint) - >>> message = str(encrypted) - >>> assert message != 'sekrit' - >>> decrypted = gpg.decrypt(message) - >>> assert decrypted - >>> str(decrypted) - 'sekrit' + >>> message = "The crow flies at midnight." + >>> encrypted = str(gpg.encrypt(message, key.printprint)) + >>> assert encrypted != message + >>> assert not encrypted.isspace() + >>> decrypted = str(gpg.decrypt(encrypted)) + >>> assert not decrypted.isspace() + >>> decrypted + 'The crow flies at midnight.' + + :param str cipher_algo: The cipher algorithm to use. To see available + algorithms with your version of GnuPG, do: + ``$ gpg --with-colons --list-config ciphername``. + The default ``cipher_algo``, if unspecified, is ``'AES256'``. + + :param str digest_algo: The hash digest to use. Again, to see which + hashes your GnuPG is capable of using, do: + ``$ gpg --with-colons --list-config digestname``. + The default, if unspecified, is ``'SHA512'``. + + :param str compress_algo: The compression algorithm to use. Can be one + of ``'ZLIB'``, ``'BZIP2'``, ``'ZIP'``, or ``'Uncompressed'``. """ stream = _make_binary_stream(data, self._encoding) - result = self.encrypt_file(stream, recipients, **kwargs) + result = self._encrypt(stream, recipients, **kwargs) stream.close() return result