Merge branch 'fix/89-python3' into develop
commit
9d8d6cce5c
|
@ -1005,7 +1005,7 @@ class GPGBase(object):
|
||||||
|
|
||||||
if output_filename:
|
if output_filename:
|
||||||
log.info("Writing encrypted output to file: %s" % output_filename)
|
log.info("Writing encrypted output to file: %s" % output_filename)
|
||||||
with open(output_filename, 'w+') as fh:
|
with open(output_filename, 'wb') as fh:
|
||||||
fh.write(result.data)
|
fh.write(result.data)
|
||||||
fh.flush()
|
fh.flush()
|
||||||
log.info("Encrypted output written successfully.")
|
log.info("Encrypted output written successfully.")
|
||||||
|
|
|
@ -167,7 +167,6 @@ def _copy_data(instream, outstream):
|
||||||
:param file outstream: The file descriptor of a tmpfile to write to.
|
:param file outstream: The file descriptor of a tmpfile to write to.
|
||||||
"""
|
"""
|
||||||
sent = 0
|
sent = 0
|
||||||
|
|
||||||
coder = find_encodings()
|
coder = find_encodings()
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
|
@ -179,24 +178,73 @@ def _copy_data(instream, outstream):
|
||||||
data = instream.read(1024)
|
data = instream.read(1024)
|
||||||
if len(data) == 0:
|
if len(data) == 0:
|
||||||
break
|
break
|
||||||
|
|
||||||
sent += len(data)
|
sent += len(data)
|
||||||
log.debug("Sending chunk %d bytes:\n%s"
|
log.debug("Sending chunk %d bytes:\n%s" % (sent, data))
|
||||||
% (sent, data))
|
|
||||||
try:
|
if _py3k and isinstance(data, bytes):
|
||||||
outstream.write(data)
|
encoded = coder.encode(data.decode(coder.name))[0]
|
||||||
except UnicodeError:
|
elif _py3k and isinstance(data, str):
|
||||||
|
encoded = coder.encode(data)[0]
|
||||||
|
elif not _py3k and type(data) is not str:
|
||||||
|
encoded = coder.encode(data)[0]
|
||||||
|
else:
|
||||||
|
encoded = data
|
||||||
|
log.debug("Writing encoded data with type %s to outstream... "
|
||||||
|
% type(encoded))
|
||||||
|
|
||||||
|
if not _py3k:
|
||||||
try:
|
try:
|
||||||
outstream.write(coder.encode(data))
|
outstream.write(encoded)
|
||||||
except IOError:
|
except IOError as ioe:
|
||||||
log.exception("Error sending data: Broken pipe")
|
# Can get 'broken pipe' errors even when all data was sent
|
||||||
|
if 'Broken pipe' in str(ioe):
|
||||||
|
log.error('Error sending data: Broken pipe')
|
||||||
|
else:
|
||||||
|
log.exception(ioe)
|
||||||
break
|
break
|
||||||
except IOError as ioe:
|
|
||||||
# Can get 'broken pipe' errors even when all data was sent
|
|
||||||
if 'Broken pipe' in str(ioe):
|
|
||||||
log.error('Error sending data: Broken pipe')
|
|
||||||
else:
|
else:
|
||||||
log.exception(ioe)
|
log.debug("Wrote data type <type 'str'> to outstream.")
|
||||||
break
|
else:
|
||||||
|
try:
|
||||||
|
outstream.write(bytes(encoded))
|
||||||
|
except TypeError as te:
|
||||||
|
# XXX FIXME This appears to happen because
|
||||||
|
# _threaded_copy_data() sometimes passes the `outstream` as an
|
||||||
|
# object with type <_io.BufferredWriter> and at other times
|
||||||
|
# with type <encodings.utf_8.StreamWriter>. We hit the
|
||||||
|
# following error when the `outstream` has type
|
||||||
|
# <encodings.utf_8.StreamWriter>.
|
||||||
|
if not "convert 'bytes' object to str implicitly" in str(te):
|
||||||
|
log.error(str(te))
|
||||||
|
try:
|
||||||
|
outstream.write(encoded.decode())
|
||||||
|
except TypeError as yate:
|
||||||
|
# We hit the "'str' does not support the buffer interface"
|
||||||
|
# error in Python3 when the `outstream` is an io.BytesIO and
|
||||||
|
# we try to write a str to it. We don't care about that
|
||||||
|
# error, we'll just try again with bytes.
|
||||||
|
if not "does not support the buffer interface" in str(yate):
|
||||||
|
log.error(str(yate))
|
||||||
|
except IOError as ioe:
|
||||||
|
# Can get 'broken pipe' errors even when all data was sent
|
||||||
|
if 'Broken pipe' in str(ioe):
|
||||||
|
log.error('Error sending data: Broken pipe')
|
||||||
|
else:
|
||||||
|
log.exception(ioe)
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
log.debug("Wrote data type <class 'str'> outstream.")
|
||||||
|
except IOError as ioe:
|
||||||
|
# Can get 'broken pipe' errors even when all data was sent
|
||||||
|
if 'Broken pipe' in str(ioe):
|
||||||
|
log.error('Error sending data: Broken pipe')
|
||||||
|
else:
|
||||||
|
log.exception(ioe)
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
log.debug("Wrote data type <class 'bytes'> to outstream.")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
outstream.close()
|
outstream.close()
|
||||||
except IOError as ioe:
|
except IOError as ioe:
|
||||||
|
|
|
@ -801,7 +801,7 @@ class GPG(GPGBase):
|
||||||
key = key.replace('_','-').title()
|
key = key.replace('_','-').title()
|
||||||
## to set 'cert', 'Key-Usage' must be blank string
|
## to set 'cert', 'Key-Usage' must be blank string
|
||||||
if not key in ('Key-Usage', 'Subkey-Usage'):
|
if not key in ('Key-Usage', 'Subkey-Usage'):
|
||||||
if str(val).strip():
|
if type(u'')(val).strip():
|
||||||
parms[key] = val
|
parms[key] = val
|
||||||
|
|
||||||
## if Key-Type is 'default', make Subkey-Type also be 'default'
|
## if Key-Type is 'default', make Subkey-Type also be 'default'
|
||||||
|
|
|
@ -26,6 +26,7 @@ A test harness and unittests for gnupg.py.
|
||||||
from __future__ import absolute_import
|
from __future__ import absolute_import
|
||||||
from __future__ import print_function
|
from __future__ import print_function
|
||||||
from __future__ import with_statement
|
from __future__ import with_statement
|
||||||
|
|
||||||
from argparse import ArgumentParser
|
from argparse import ArgumentParser
|
||||||
from codecs import open as open
|
from codecs import open as open
|
||||||
from functools import wraps
|
from functools import wraps
|
||||||
|
@ -389,7 +390,10 @@ class GPGTestCase(unittest.TestCase):
|
||||||
def test_gen_key_input(self):
|
def test_gen_key_input(self):
|
||||||
"""Test that GnuPG batch file creation is successful."""
|
"""Test that GnuPG batch file creation is successful."""
|
||||||
key_input = self.generate_key_input("Francisco Ferrer", "an.ok")
|
key_input = self.generate_key_input("Francisco Ferrer", "an.ok")
|
||||||
self.assertIsInstance(key_input, str)
|
if _util._py3k:
|
||||||
|
self.assertIsInstance(key_input, str)
|
||||||
|
else:
|
||||||
|
self.assertIsInstance(key_input, basestring)
|
||||||
self.assertGreater(key_input.find('Francisco Ferrer'), 0)
|
self.assertGreater(key_input.find('Francisco Ferrer'), 0)
|
||||||
|
|
||||||
def test_rsa_key_generation(self):
|
def test_rsa_key_generation(self):
|
||||||
|
@ -777,14 +781,12 @@ authentication."""
|
||||||
log.debug("Encrypted: %s" % encrypted)
|
log.debug("Encrypted: %s" % encrypted)
|
||||||
self.assertNotEquals(message, encrypted)
|
self.assertNotEquals(message, encrypted)
|
||||||
|
|
||||||
def test_encryption_of_file_like_objects(self):
|
def _encryption_test_setup(self):
|
||||||
"""Test encryption of file-like objects"""
|
passphrase = "craiggentry"
|
||||||
key = self.generate_key("Craig Gentry", "xorr.ox",
|
key = self.generate_key("Craig Gentry", "xorr.ox", passphrase=passphrase)
|
||||||
passphrase="craiggentry")
|
fpr = str(key.fingerprint)
|
||||||
gentry_fpr = str(key.fingerprint)
|
|
||||||
gentry = self.gpg.export_keys(key.fingerprint)
|
gentry = self.gpg.export_keys(key.fingerprint)
|
||||||
self.gpg.import_keys(gentry)
|
self.gpg.import_keys(gentry)
|
||||||
|
|
||||||
message = """
|
message = """
|
||||||
In 2010 Riggio and Sicari presented a practical application of homomorphic
|
In 2010 Riggio and Sicari presented a practical application of homomorphic
|
||||||
encryption to a hybrid wireless sensor/mesh network. The system enables
|
encryption to a hybrid wireless sensor/mesh network. The system enables
|
||||||
|
@ -792,32 +794,63 @@ transparent multi-hop wireless backhauls that are able to perform statistical
|
||||||
analysis of different kinds of data (temperature, humidity, etc.) coming from
|
analysis of different kinds of data (temperature, humidity, etc.) coming from
|
||||||
a WSN while ensuring both end-to-end encryption and hop-by-hop
|
a WSN while ensuring both end-to-end encryption and hop-by-hop
|
||||||
authentication."""
|
authentication."""
|
||||||
|
return (message, fpr, passphrase)
|
||||||
|
|
||||||
def _encryption_test_wrapper(stream_type, message):
|
def _encryption_test(self, stream_type, message, fingerprint, passphrase):
|
||||||
stream = stream_type(message)
|
stream = stream_type(message)
|
||||||
encrypted = str(self.gpg.encrypt(stream, gentry_fpr))
|
encrypted = self.gpg.encrypt(stream, fingerprint).data
|
||||||
decrypted = str(self.gpg.decrypt(encrypted,
|
decrypted = self.gpg.decrypt(encrypted, passphrase=passphrase).data
|
||||||
passphrase="craiggentry"))
|
|
||||||
self.assertEqual(message, decrypted)
|
if isinstance(decrypted, bytes):
|
||||||
|
decrypted = decrypted.decode()
|
||||||
|
if isinstance(message, bytes):
|
||||||
|
message = message.decode()
|
||||||
|
|
||||||
|
self.assertEqual(message, decrypted)
|
||||||
|
|
||||||
|
def test_encryption_of_file_like_objects_io_StringIO(self):
|
||||||
|
"""Test encryption of file-like object io.StringIO."""
|
||||||
|
message, fpr, passphrase = self._encryption_test_setup()
|
||||||
|
|
||||||
# Test io.StringIO and io.BytesIO (Python 2.6+)
|
|
||||||
try:
|
try:
|
||||||
from io import StringIO, BytesIO
|
from io import StringIO
|
||||||
_encryption_test_wrapper(StringIO, unicode(message))
|
if _util._py3k:
|
||||||
_encryption_test_wrapper(BytesIO, message)
|
self._encryption_test(StringIO, message, fpr, passphrase)
|
||||||
|
else:
|
||||||
|
self._encryption_test(StringIO, unicode(message), fpr, passphrase)
|
||||||
except ImportError:
|
except ImportError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
# Test StringIO.StringIO
|
def test_encryption_of_file_like_objects_io_BytesIO(self):
|
||||||
from StringIO import StringIO
|
"""Test encryption of file-like object io.BytesIO."""
|
||||||
_encryption_test_wrapper(StringIO, message)
|
message, fpr, passphrase = self._encryption_test_setup()
|
||||||
|
|
||||||
# Test cStringIO.StringIO
|
try:
|
||||||
from cStringIO import StringIO
|
from io import BytesIO
|
||||||
_encryption_test_wrapper(StringIO, message)
|
if _util._py3k:
|
||||||
|
self._encryption_test(BytesIO, bytes(message, 'utf-8'), fpr, passphrase)
|
||||||
|
else:
|
||||||
|
self._encryption_test(BytesIO, message, fpr, passphrase)
|
||||||
|
except ImportError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def test_encryption_of_file_like_objects_StringIO_StringIO(self):
|
||||||
|
"""Test encryption of file-like object StringIO.StringIO (Python2 only)."""
|
||||||
|
message, fpr, passphrase = self._encryption_test_setup()
|
||||||
|
|
||||||
|
if not _util._py3k:
|
||||||
|
from StringIO import StringIO
|
||||||
|
self._encryption_test(StringIO, message, fpr, passphrase)
|
||||||
|
|
||||||
|
def test_encryption_of_file_like_objects_cStringIO_StringIO(self):
|
||||||
|
"""Test encryption of file-like object cStringIO.StringIO (Python2 only)."""
|
||||||
|
message, fpr, passphrase = self._encryption_test_setup()
|
||||||
|
|
||||||
|
if not _util._py3k:
|
||||||
|
from cStringIO import StringIO
|
||||||
|
self._encryption_test(StringIO, message, fpr, passphrase)
|
||||||
|
|
||||||
def test_encryption_alt_encoding(self):
|
def test_encryption_alt_encoding(self):
|
||||||
|
|
||||||
"""Test encryption with latin-1 encoding"""
|
"""Test encryption with latin-1 encoding"""
|
||||||
key = self.generate_key("Craig Gentry", "xorr.ox",
|
key = self.generate_key("Craig Gentry", "xorr.ox",
|
||||||
passphrase="craiggentry")
|
passphrase="craiggentry")
|
||||||
|
@ -825,11 +858,7 @@ authentication."""
|
||||||
key = self.generate_key("Marten van Dijk", "xorr.ox")
|
key = self.generate_key("Marten van Dijk", "xorr.ox")
|
||||||
dijk = str(key.fingerprint)
|
dijk = str(key.fingerprint)
|
||||||
self.gpg._encoding = 'latin-1'
|
self.gpg._encoding = 'latin-1'
|
||||||
if _util._py3k:
|
data = u'Hello, André!'.encode(self.gpg._encoding)
|
||||||
data = 'Hello, André!'
|
|
||||||
else:
|
|
||||||
data = unicode('Hello, André', self.gpg._encoding)
|
|
||||||
data = data.encode(self.gpg._encoding)
|
|
||||||
encrypted = self.gpg.encrypt(data, gentry)
|
encrypted = self.gpg.encrypt(data, gentry)
|
||||||
edata = str(encrypted.data)
|
edata = str(encrypted.data)
|
||||||
self.assertNotEqual(data, edata)
|
self.assertNotEqual(data, edata)
|
||||||
|
@ -998,7 +1027,8 @@ boolean circuit causes a considerable overhead."""
|
||||||
## We expect Alice's key to be hidden (returned as zero's) and Bob's
|
## We expect Alice's key to be hidden (returned as zero's) and Bob's
|
||||||
## key to be there.
|
## key to be there.
|
||||||
expected_values = ["0000000000000000", "0000000000000000"]
|
expected_values = ["0000000000000000", "0000000000000000"]
|
||||||
self.assertEquals(expected_values, self.gpg.list_packets(encrypted).encrypted_to)
|
packets = self.gpg.list_packets(encrypted)
|
||||||
|
self.assertEquals(expected_values, packets.encrypted_to)
|
||||||
|
|
||||||
def test_encryption_decryption_multi_recipient(self):
|
def test_encryption_decryption_multi_recipient(self):
|
||||||
"""Test decryption of an encrypted string for multiple users"""
|
"""Test decryption of an encrypted string for multiple users"""
|
||||||
|
@ -1187,7 +1217,10 @@ suites = { 'parsers': set(['test_parsers_fix_unsafe',
|
||||||
'test_signature_string_verification',
|
'test_signature_string_verification',
|
||||||
'test_signature_string_algorithm_encoding']),
|
'test_signature_string_algorithm_encoding']),
|
||||||
'crypt': set(['test_encryption',
|
'crypt': set(['test_encryption',
|
||||||
'test_encryption_of_file_like_objects',
|
'test_encryption_of_file_like_objects_io_StringIO',
|
||||||
|
'test_encryption_of_file_like_objects_io_BytesIO',
|
||||||
|
'test_encryption_of_file_like_objects_StringIO_StringIO',
|
||||||
|
'test_encryption_of_file_like_objects_cStringIO_StringIO',
|
||||||
'test_encryption_alt_encoding',
|
'test_encryption_alt_encoding',
|
||||||
'test_encryption_multi_recipient',
|
'test_encryption_multi_recipient',
|
||||||
'test_encryption_decryption_multi_recipient',
|
'test_encryption_decryption_multi_recipient',
|
||||||
|
|
Loading…
Reference in New Issue