def test_firmware_pass(algo): # test firmware decryption with wrong and correct password firmware = Firmware("firmwares/{}.pass.firmware.bin".format(algo), UDID) assert firmware.locked assert not firmware.unlock(WRONGPW) assert firmware.unlock(GOODPW) assert not firmware.locked # extract private key from firmware pubkey, _ = PGPKey.from_file("pubkeys/{}.pub.key.asc".format(algo)) privkey = firmware.extract_key(pubkey) assert privkey is not None # test message decryption subk = get_key_with_flag(privkey, KeyFlags.EncryptCommunications) assert subk is not None enc = PGPMessage.from_file("messages/{}.enc.msg.gpg".format(algo)) dec = subk.decrypt(enc) assert bytes(dec.message) == MESSAGE # test signature subk = get_key_with_flag(privkey, KeyFlags.Sign) assert subk is not None msg = PGPMessage.new(MESSAGE, compression=CompressionAlgorithm.Uncompressed) sig = subk.sign(msg) subk = get_key_with_flag(pubkey, KeyFlags.Sign) assert subk is not None assert subk.verify(MESSAGE, sig)
def test_firmware_nopass(algo): # extract private key from firmware firmware = Firmware("firmwares/{}.firmware.bin".format(algo), UDID) assert not firmware.locked pubkey, _ = PGPKey.from_file("pubkeys/{}.pub.key.asc".format(algo)) privkey = firmware.extract_key(pubkey) assert privkey is not None # test message decryption subk = get_key_with_flag(privkey, KeyFlags.EncryptCommunications) assert subk is not None enc = PGPMessage.from_file("messages/{}.enc.msg.gpg".format(algo)) dec = subk.decrypt(enc) assert bytes(dec.message) == MESSAGE # test signature: except Ed25519 which cannot be extracted subk = get_key_with_flag(privkey, KeyFlags.Sign) if algo != 'curve25519': assert subk is not None msg = PGPMessage.new(MESSAGE, compression=CompressionAlgorithm.Uncompressed) sig = subk.sign(msg) subk = get_key_with_flag(pubkey, KeyFlags.Sign) assert subk is not None assert subk.verify(MESSAGE, sig) else: assert subk is None
def test_gpg_cv25519_decrypt(self, abe): # test the decryption of X25519 generated by GnuPG seckey, _ = PGPKey.from_file('tests/testdata/keys/ecc.2.sec.asc') emsg = PGPMessage.from_file( 'tests/testdata/messages/message.ecdh.cv25519.asc') with warnings.catch_warnings(): warnings.simplefilter('ignore') dmsg = seckey.decrypt(emsg) assert bytes(dmsg.message) == b"This message will have been encrypted"
def test_load_from_file(self, msgfile): # TODO: figure out a good way to verify that all went well here, because # PGPy reorders signatures sometimes, and also unwraps compressed messages # so comparing str(msg) to the contents of msgfile doesn't actually work msg = PGPMessage.from_file(msgfile) with open(msgfile, 'r') as mf: mt = mf.read() assert len(str(msg)) == len(mt)
def test_load_from_file(self, msgfile): # TODO: figure out a good way to verify that all went well here, because # PGPy reorders signatures sometimes, and also unwraps compressed messages # so comparing str(msg) to the contents of msgfile doesn't actually work msg = PGPMessage.from_file(msgfile) with open(msgfile, 'r') as mf: mt = mf.read() assert len(str(msg)) == len(mt)
from pgpy.constants import CompressionAlgorithm from pgpy.constants import EllipticCurveOID from pgpy.constants import Features from pgpy.constants import HashAlgorithm from pgpy.constants import KeyFlags from pgpy.constants import KeyServerPreferences from pgpy.constants import PubKeyAlgorithm from pgpy.constants import RevocationReason from pgpy.constants import SignatureType from pgpy.constants import SymmetricKeyAlgorithm from pgpy.packet import Packet from pgpy.packet.packets import PrivKeyV4 from pgpy.packet.packets import PrivSubKeyV4 enc_msgs = [ PGPMessage.from_file(f) for f in sorted(glob.glob('tests/testdata/messages/message*.pass*.asc')) ] class TestPGPMessage(object): @staticmethod def gpg_message(msg): with gpg.Context(offline=True) as c: c.set_engine_info(gpg.constants.PROTOCOL_OpenPGP, home_dir=gnupghome) msg, _ = c.verify(gpg.Data(string=str(msg))) return msg @staticmethod def gpg_decrypt(msg, passphrase): try: with gpg.Context(armor=True, offline=True, pinentry_mode=gpg.constants.PINENTRY_MODE_LOOPBACK) as c: c.set_engine_info(gpg.constants.PROTOCOL_OpenPGP, file_name='/usr/bin/gpg', home_dir=gnupghome)
def test_decrypt_unencrypted(self): msg = PGPMessage.from_file('tests/testdata/messages/message.signed.asc') with pytest.raises(PGPError): msg.decrypt("Password")
class TestPGPMessage(object): params = { 'comp_alg': comp_algs, 'enc_msg': [ PGPMessage.from_file(f) for f in glob.glob('tests/testdata/messages/message*.pass*.asc') ], 'file': sorted(glob.glob('tests/testdata/files/literal*')), } ids = { 'test_new': [str(ca).split('.')[-1] for ca in comp_algs], 'test_new_from_file': [os.path.basename(fn).replace('.', '_') for fn in params['file']], } attrs = { 'tests/testdata/files/literal.1.txt': [('filename', 'literal.1.txt'), ('message', os.linesep.join(['This is stored, literally\!', os.linesep]))], 'tests/testdata/files/literal.2.txt': [ ('filename', 'literal.2.txt'), ('message', os.linesep.join(['This is stored, literally!', os.linesep])) ], 'tests/testdata/files/literal.dashesc.txt': [('filename', 'literal.dashesc.txt'), ('message', os.linesep.join([ 'The following items are stored, literally:', '- This one', '- Also this one', '- And finally, this one!', os.linesep ]))], 'tests/testdata/files/literal.bin': [('filename', 'literal.bin'), ('message', bytearray(range(256)))], } def test_new(self, comp_alg, write_clean, gpg_print): msg = PGPMessage.new(u"This is a new message!", compression=comp_alg) assert msg.filename == '' assert msg.type == 'literal' assert msg.message == u"This is a new message!" assert msg._message.format == 'u' assert msg._message.filename == '' assert msg.is_compressed is bool( comp_alg != CompressionAlgorithm.Uncompressed) with write_clean('tests/testdata/cmsg.asc', 'w', str(msg)): assert gpg_print('cmsg.asc') == "This is a new message!" def test_new_sensitive(self, write_clean, gpg_print): msg = PGPMessage.new("This is a sensitive message!", sensitive=True) assert msg.type == 'literal' assert msg.message == "This is a sensitive message!" assert msg.is_sensitive assert msg.filename == '_CONSOLE' with write_clean('tests/testdata/csmsg.asc', 'w', str(msg)): assert gpg_print('csmsg.asc') == "This is a sensitive message!" @pytest.mark.regression(issue=154) def test_new_non_unicode(self, write_clean, gpg_print): # this message text comes from http://www.columbia.edu/~fdc/utf8/ text = u'色は匂へど 散りぬるを\n' \ u'我が世誰ぞ 常ならむ\n' \ u'有為の奥山 今日越えて\n' \ u'浅き夢見じ 酔ひもせず\n' msg = PGPMessage.new(text.encode('jisx0213'), encoding='jisx0213') assert msg.type == 'literal' assert msg.message == text.encode('jisx0213') @pytest.mark.regression(issue=154) def test_new_non_unicode_cleartext(self, write_clean, gpg_print): # this message text comes from http://www.columbia.edu/~fdc/utf8/ text = u'色は匂へど 散りぬるを\n' \ u'我が世誰ぞ 常ならむ\n' \ u'有為の奥山 今日越えて\n' \ u'浅き夢見じ 酔ひもせず\n' msg = PGPMessage.new(text.encode('jisx0213'), cleartext=True, encoding='jisx0213') assert msg.type == 'cleartext' assert msg.message == text def test_new_from_file(self, file, write_clean, gpg_print): msg = PGPMessage.new(file, file=True) assert isinstance(msg, PGPMessage) assert msg.type == 'literal' assert msg.is_sensitive is False assert file in self.attrs for attr, expected in self.attrs[file]: val = getattr(msg, attr) assert val == expected with write_clean('tests/testdata/cmsg.asc', 'w', str(msg)): out = gpg_print('cmsg.asc') if msg._message.format == 'b': out = out.encode('latin-1') assert out == msg.message def test_add_marker(self): msg = PGPMessage.new(u"This is a new message") marker = Packet(bytearray(b'\xa8\x03\x50\x47\x50')) msg |= marker def test_decrypt_passphrase_message(self, enc_msg): decmsg = enc_msg.decrypt("QwertyUiop") assert isinstance(decmsg, PGPMessage) assert decmsg.message == b"This is stored, literally\\!\n\n" def test_encrypt_passphrase(self, write_clean, gpg_decrypt): msg = PGPMessage.new("This message is to be encrypted") encmsg = msg.encrypt("QwertyUiop") # make sure lit was untouched assert not msg.is_encrypted # make sure encmsg is encrypted assert encmsg.is_encrypted assert encmsg.type == 'encrypted' # decrypt with PGPy decmsg = encmsg.decrypt("QwertyUiop") assert isinstance(decmsg, PGPMessage) assert decmsg.type == msg.type assert decmsg.is_compressed assert decmsg.message == msg.message # decrypt with GPG with write_clean('tests/testdata/semsg.asc', 'w', str(encmsg)): assert gpg_decrypt( './semsg.asc', "QwertyUiop") == "This message is to be encrypted" def test_encrypt_passphrase_2(self, write_clean, gpg_decrypt): msg = PGPMessage.new("This message is to be encrypted") sk = SymmetricKeyAlgorithm.AES256.gen_key() encmsg = msg.encrypt("QwertyUiop", sessionkey=sk).encrypt("AsdfGhjkl", sessionkey=sk) # make sure lit was untouched assert not msg.is_encrypted # make sure encmsg is encrypted assert encmsg.is_encrypted assert encmsg.type == 'encrypted' assert len(encmsg._sessionkeys) == 2 # decrypt with PGPy for passphrase in ["QwertyUiop", "AsdfGhjkl"]: decmsg = encmsg.decrypt(passphrase) assert isinstance(decmsg, PGPMessage) assert decmsg.type == msg.type assert decmsg.is_compressed assert decmsg.message == msg.message
from pgpy.constants import CompressionAlgorithm from pgpy.constants import EllipticCurveOID from pgpy.constants import Features from pgpy.constants import HashAlgorithm from pgpy.constants import KeyFlags from pgpy.constants import KeyServerPreferences from pgpy.constants import PubKeyAlgorithm from pgpy.constants import RevocationReason from pgpy.constants import SignatureType from pgpy.constants import SymmetricKeyAlgorithm from pgpy.packet import Packet from pgpy.packet.packets import PrivKeyV4 from pgpy.packet.packets import PrivSubKeyV4 enc_msgs = [ PGPMessage.from_file(f) for f in sorted(glob.glob('tests/testdata/messages/message*.pass*.asc')) ] class TestPGPMessage(object): @staticmethod def gpg_message(msg): with gpg.Context(offline=True) as c: c.set_engine_info(gpg.constants.PROTOCOL_OpenPGP, home_dir=gnupghome) msg, _ = c.verify(gpg.Data(string=str(msg))) return msg @staticmethod def gpg_decrypt(msg, passphrase):
def test_decrypt_wrongpass(self): msg = PGPMessage.from_file( next(f for f in glob.glob( 'tests/testdata/messages/message*.pass*.asc'))) with pytest.raises(PGPDecryptionError): msg.decrypt("TheWrongPassword")
from pgpy.constants import CompressionAlgorithm from pgpy.constants import EllipticCurveOID from pgpy.constants import Features from pgpy.constants import HashAlgorithm from pgpy.constants import KeyFlags from pgpy.constants import KeyServerPreferences from pgpy.constants import PubKeyAlgorithm from pgpy.constants import RevocationReason from pgpy.constants import SignatureType from pgpy.constants import SymmetricKeyAlgorithm from pgpy.packet import Packet from pgpy.packet.packets import PrivKeyV4 from pgpy.packet.packets import PrivSubKeyV4 enc_msgs = [ PGPMessage.from_file(f) for f in sorted(glob.glob('tests/testdata/messages/message*.pass*.asc')) ] class TestPGPMessage(object): @pytest.mark.parametrize('comp_alg,sensitive', itertools.product(CompressionAlgorithm, [False, True])) def test_new(self, comp_alg, sensitive, gpg_print): mtxt = u"This is a new message!" msg = PGPMessage.new(mtxt, compression=comp_alg, sensitive=sensitive) assert isinstance(msg, PGPMessage) assert msg.filename == ('_CONSOLE' if sensitive else '') assert msg.is_sensitive is sensitive assert msg.type == 'literal' assert msg.message == mtxt assert msg._compression == comp_alg
# integers are kind of a special case. # ints that do not exceed sys.maxsize are singletons, and in either case are immutable # this shouldn't apply to MPIs, though, which are subclasses of int if isinstance(obj, int) and not isinstance(obj, pgpy.packet.types.MPI): return False return True def ksort(key): # return a tuple of key, key.count('.') so we get a descending alphabetical, ascending depth ordering return key, key.count('.') objs = [sig(), uid(),] + [PGPMessage.from_file(m) for m in _msgs] + [key(f) for f in _keys] cids = ['sig', 'uid',] + [os.path.basename(m) for m in _msgs] + [os.path.basename(f) for f in _keys] @pytest.mark.parametrize('obj', objs, ids=cids) def test_copy_obj(request, obj): obj2 = copy.copy(obj) objflat = {name: val for name, val in walk_obj(obj, '{}.'.format(request.node.callspec.id))} obj2flat = {name: val for name, val in walk_obj(obj2, '{}.'.format(request.node.callspec.id))} for k in sorted(objflat, key=ksort): print("checking attribute: {} ".format(k), end="") if isinstance(objflat[k], pgpy.types.SorteDeque): print("[SorteDeque] ", end="") assert len(objflat[k]) == len(obj2flat[k])
# this shouldn't apply to MPIs, though, which are subclasses of int if isinstance(obj, int) and not isinstance(obj, pgpy.packet.types.MPI): return False return True def ksort(key): # return a tuple of key, key.count('.') so we get a descending alphabetical, ascending depth ordering return key, key.count('.') objs = [ sig(), uid(), ] + [PGPMessage.from_file(m) for m in _msgs] + [key(f) for f in _keys] cids = [ 'sig', 'uid', ] + [os.path.basename(m) for m in _msgs] + [os.path.basename(f) for f in _keys] @pytest.mark.parametrize('obj', objs, ids=cids) def test_copy_obj(request, obj): obj2 = copy.copy(obj) objflat = { name: val for name, val in walk_obj(obj, '{}.'.format(request.node.callspec.id)) }
class TestCopy(object): params = { 'obj': [sig(), uid()] + [PGPMessage.from_file(m) for m in _msgs] + [key(fn) for fn in _keys], } ids = { 'test_copy_obj': ['sig', 'uid'] + ['-'.join(os.path.basename(fn).split('.')[:3]) for fn in _msgs] + ['-'.join(os.path.basename(fn).split('.')[:3]) for fn in _keys], } @staticmethod def check_id(obj): from datetime import datetime from enum import Enum # do some type checking to determine if we should check the identity of an object member # these types are singletons if isinstance(obj, (Enum, bool, type(None))): return False # these types are immutable if isinstance(obj, (six.string_types, datetime)): return False # integers are kind of a special case. # ints that do not exceed sys.maxsize are singletons, and in either case are immutable # this shouldn't apply to MPIs, though, which are subclasses of int if isinstance(obj, int) and not isinstance(obj, pgpy.packet.types.MPI): return False return True @staticmethod def ksort(key): # return a tuple of key, key.count('.') so we get a descending alphabetical, ascending depth ordering return key, key.count('.') def test_copy_obj(self, request, obj): obj2 = copy.copy(obj) objflat = { name: val for name, val in walk_obj(obj, '{}.'.format( request.node.callspec.id)) } obj2flat = { name: val for name, val in walk_obj(obj2, '{}.'.format( request.node.callspec.id)) } for k in sorted(objflat, key=self.ksort): print("checking attribute: {} ".format(k), end="") if isinstance(objflat[k], pgpy.types.SorteDeque): print("[SorteDeque] ", end="") assert len(objflat[k]) == len(obj2flat[k]) if not isinstance(objflat[k], (pgpy.types.PGPObject, pgpy.types.SorteDeque)): print("[{} ]".format(type(objflat[k])), end="") assert objflat[k] == objflat[k], k # check identity, but only types that should definitely be copied if self.check_id(objflat[k]): print("[id] {}".format(type(objflat[k]))) assert objflat[k] is not obj2flat[k], "{}: {}".format( type(objflat[k]), k) else: print()
def test_decrypt_wrongkey(self, targette_sec): msg = PGPMessage.from_file( 'tests/testdata/messages/message.rsa.cast5.asc') with pytest.raises(PGPError): targette_sec.decrypt(msg)
def test_decrypt_unsupported_algorithm(self): msg = PGPMessage.from_file('tests/testdata/message.enc.twofish.asc') with pytest.raises(PGPDecryptionError): msg.decrypt("QwertyUiop")
def test_decrypt_wrongkey(self, targette_sec): msg = PGPMessage.from_file('tests/testdata/messages/message.rsa.cast5.asc') with pytest.raises(PGPError): targette_sec.decrypt(msg)
def test_decrypt_unencrypted(self): msg = PGPMessage.from_file( 'tests/testdata/messages/message.signed.asc') with pytest.raises(PGPError): msg.decrypt("Password")
def test_decrypt_unsupported_algorithm(self): msg = PGPMessage.from_file('tests/testdata/message.enc.twofish.asc') with pytest.raises(PGPDecryptionError): msg.decrypt("QwertyUiop")
def test_decrypt_wrongpass(self): msg = PGPMessage.from_file(next(f for f in glob.glob('tests/testdata/messages/message*.pass*.asc'))) with pytest.raises(PGPDecryptionError): msg.decrypt("TheWrongPassword")
from pgpy import PGPKey, PGPMessage, constants from pyspark.sql.types import StructType, StructField, StringType, IntegerType from pyspark.sql.functions import percent_rank, col from pyspark.sql.window import Window if 'PYSPARK_DRIVER_PYTHON' not in os.environ.keys( ) and 'PYSPARK_DRIVER_PYTHON' not in os.environ.keys(): os.environ['PYSPARK_DRIVER_PYTHON'] = 'python3.6' os.environ['PYSPARK_PYTHON'] = 'python3.6' # Decrypt CSV file # https://pgpy.readthedocs.io/en/latest/examples.html titanic = open('titanic.csv', 'w') key, _ = PGPKey.from_file('slim.shady.sec.asc') message_from_blob = PGPMessage.from_file('titanic.csv.gpg') dec_mess = key.decrypt(message_from_blob) csv_result = dec_mess.message titanic.write(csv_result.decode('UTF-8')) # Setting up our DataFrame sc = pyspark.SparkContext() sql_ctx = pyspark.SQLContext(sc) # Explicitly setting the schema type - may be unnecessary # Notes: https://stackoverflow.com/questions/44706398/spark-csv-reader-quoted-numerics schema = StructType([ StructField("RecId", IntegerType(), True), StructField("Name", StringType(), True), StructField("PassengerClass", StringType(), True), StructField("Age", IntegerType(), True),