def test_encrypt_message_select_uid(self): # generate a temporary key with two UIDs, then encrypt a message u1 = PGPUID.new('UID One') u2 = PGPUID.new('UID Two') k = PGPKey.new(PubKeyAlgorithm.RSAEncryptOrSign, 512) flags = { KeyFlags.Certify, KeyFlags.Sign, KeyFlags.EncryptCommunications, KeyFlags.EncryptStorage } k.add_uid(u1, usage=flags, hashes=[HashAlgorithm.SHA1], ciphers=[SymmetricKeyAlgorithm.AES128]) k.add_uid(u2, usage=flags, hashes=[HashAlgorithm.SHA1], ciphers=[SymmetricKeyAlgorithm.Camellia128]) emsg = k.pubkey.encrypt( PGPMessage.new('This message is about to be encrypted'), user='******') # assert that it was encrypted with Camellia128 and that we can decrypt it normally assert emsg._sessionkeys[0].decrypt_sk( k._key)[0] == SymmetricKeyAlgorithm.Camellia128 assert k.decrypt( emsg).message == 'This message is about to be encrypted'
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_decrypt_unencrypted_message(self, rsa_sec, recwarn): lit = PGPMessage.new('tests/testdata/lit', file=True) rsa_sec.decrypt(lit) w = recwarn.pop(UserWarning) assert str(w.message) == "This message is not encrypted" assert w.filename == __file__
def sign_encrypt(profile, data, addr, recipients): pmsg = data if isinstance(data, PGPMessage) else PGPMessage.new(data) sig = sign(profile, pmsg, addr) pmsg |= sig assert pmsg.is_signed cmsg = encrypt(profile, pmsg, recipients) return cmsg
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_encrypt_passphrase(self, comp_alg, gpg_decrypt): mtxt = "This message is to be encrypted" msg = PGPMessage.new(mtxt, compression=comp_alg) assert not msg.is_encrypted encmsg = msg.encrypt("QwertyUiop") assert isinstance(encmsg, PGPMessage) 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 == msg.is_compressed assert decmsg.message == mtxt assert decmsg._compression == msg._compression # decrypt with GPG with tempfile.NamedTemporaryFile('w+') as mf: mf.write(str(encmsg)) mf.flush() assert gpg_decrypt(mf.name, "QwertyUiop") == mtxt
def encrypt(profile, data, recipients): assert isinstance(recipients, list) msg = data if isinstance(data, PGPMessage) else PGPMessage.new(data) # pmsg |= seckey.sign(msg) if len(recipients) == 1: key = _get_pubkey_from_addr(profile, recipients[0]) if key is None: logger.error('No key found to encrypt message.') return None pubkey = key if key.is_public else key.pubkey cmsg = pubkey.encrypt(msg) else: # The symmetric cipher should be specified, in case the first # preferred cipher is not the same for all recipients public # keys. cipher = SymmetricKeyAlgorithm.AES256 sessionkey = cipher.gen_key() cmsg = msg for r in recipients: key = _get_pubkey_from_addr(profile, r) if key is None: logger.error('No key found to encrypt message.') break pubkey = key if key.is_public else key.pubkey cmsg = pubkey.encrypt(cmsg, cipher=cipher, sessionkey=sessionkey) del sessionkey return cmsg
def test_sign_bad_prefs(self, rsa_sec, recwarn): rsa_sec.subkeys['2A834D8E5918E886'].sign(PGPMessage.new('asdf'), hash=HashAlgorithm.RIPEMD160) w = recwarn.pop(UserWarning) assert str( w.message) == "Selected hash algorithm not in key preferences" assert w.filename == __file__
def encrypt(message: str, key: bytes) -> str: import pgpy from pgpy import PGPMessage from pgpy.constants import CompressionAlgorithm message = PGPMessage.new(message, compression=CompressionAlgorithm.Uncompressed) pub_key, _ = pgpy.PGPKey.from_blob(key) return str(pub_key.encrypt(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!"
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')
def test_new_non_unicode_cleartext(self): # this message text comes from http://www.columbia.edu/~fdc/utf8/ text = u'色は匂へど 散りぬるを\n' \ u'我が世誰ぞ 常ならむ\n' \ u'有為の奥山 今日越えて\n' \ u'浅き夢見じ 酔ひもせず' msg = PGPMessage.new(text.encode('jisx0213'), cleartext=True, encoding='jisx0213') assert msg.type == 'cleartext' assert msg.message == text
def test_encrypt_bad_cipher(self, rsa_pub, recwarn): rsa_pub.subkeys['EEE097A017B979CA'].encrypt(PGPMessage.new('asdf'), cipher=SymmetricKeyAlgorithm.CAST5) w = recwarn.pop(UserWarning) assert str(w.message) == "Selected symmetric algorithm not in key preferences" assert w.filename == __file__ w = recwarn.pop(UserWarning) assert str(w.message) == "Selected compression algorithm not in key preferences" assert w.filename == __file__
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_encrypt_message(self, pub, cipher): if pub.key_algorithm in {PubKeyAlgorithm.DSA}: pytest.skip('Asymmetric encryption only implemented for RSA/ECDH currently') if cipher in {SymmetricKeyAlgorithm.Plaintext, SymmetricKeyAlgorithm.Twofish256, SymmetricKeyAlgorithm.IDEA}: pytest.xfail('Symmetric cipher {} not supported for encryption'.format(cipher)) # test encrypting a message mtxt = "This message will have been encrypted" msg = PGPMessage.new(mtxt) emsg = pub.encrypt(msg, cipher=cipher) self.msgs[(pub.fingerprint, cipher)] = emsg
def test_new(self, comp_alg, sensitive): 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 # see if GPG can parse our message assert self.gpg_message(msg).decode('utf-8') == mtxt
def test_new_from_file(self, comp_alg, sensitive, path): msg = PGPMessage.new(path, file=True, compression=comp_alg, sensitive=sensitive) assert isinstance(msg, PGPMessage) assert msg.filename == ('_CONSOLE' if sensitive else os.path.basename(path)) assert msg.type == 'literal' assert msg.is_sensitive is sensitive with open(path, 'rb') as tf: mtxt = tf.read() # see if GPG can parse our message assert self.gpg_message(msg) == mtxt
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_non_unicode(self): # this message text comes from http://www.columbia.edu/~fdc/utf8/ text = u'色は匂へど 散りぬるを\n' \ u'我が世誰ぞ 常ならむ\n' \ u'有為の奥山 今日越えて\n' \ u'浅き夢見じ 酔ひもせず' msg = PGPMessage.new(text.encode('jisx0213'), encoding='jisx0213') assert msg.type == 'literal' assert msg.message == text.encode('jisx0213') # see if GPG can parse our message assert self.gpg_message(msg).decode('jisx0213') == text
def main(): parser = argparse.ArgumentParser( description='''Encrypting a relatively small message''') parser.add_argument('pubkey', help='PGP public key') parser.add_argument('file', help='File to encrypt') args = parser.parse_args() message = PGPMessage.new(args.file, file=True) key, _ = PGPKey.from_file(args.pubkey) enc = key.encrypt(message) sys.stdout.buffer.write(bytes(enc))
def _encrypt_message(message_to_encrypt, server_secret, client_secret): """ Encrypts a message (from a String) :param message_to_encrypt: The message we're encrypting :param server_secret: The server secret, obtained by inspecting a package :param client_secret: The client secret, obtained by inspecting a package :return: The encrypted message """ passphrase = server_secret + client_secret message = PGPMessage.new(message_to_encrypt, compression=CompressionAlgorithm.Uncompressed) cipher_message = message.encrypt(passphrase=passphrase, cipher=SymmetricKeyAlgorithm.AES256, hash=HashAlgorithm.SHA256) return base64.b64encode(bytes(cipher_message)).decode('utf-8')
def test_new_non_unicode_cleartext(self, gpg_print): # this message text comes from http://www.columbia.edu/~fdc/utf8/ text = u'色は匂へど 散りぬるを\n' \ u'我が世誰ぞ 常ならむ\n' \ u'有為の奥山 今日越えて\n' \ u'浅き夢見じ 酔ひもせず' msg = PGPMessage.new(text.encode('jisx0213'), cleartext=True, encoding='jisx0213') assert msg.type == 'cleartext' assert msg.message == text with tempfile.NamedTemporaryFile('w+') as mf: mf.write(six.text_type(msg).encode('utf-8') if six.PY2 else six.text_type(msg)) mf.flush() assert gpg_print(mf.name).encode('latin-1').decode('utf-8').strip() == text
def test_new_from_file(self, comp_alg, sensitive, path, gpg_print): msg = PGPMessage.new(path, file=True, compression=comp_alg, sensitive=sensitive) assert isinstance(msg, PGPMessage) assert msg.filename == ('_CONSOLE' if sensitive else os.path.basename(path)) assert msg.type == 'literal' assert msg.is_sensitive is sensitive with open(path, 'rb') as tf: mtxt = tf.read().decode('latin-1') with tempfile.NamedTemporaryFile('w+') as mf: mf.write(str(msg)) mf.flush() assert gpg_print(mf.name) == mtxt
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 with tempfile.NamedTemporaryFile('w+') as mf: mf.write(str(msg)) mf.flush() assert gpg_print(mf.name) == mtxt
def test_encrypt_message_select_uid(self): # generate a temporary key with two UIDs, then encrypt a message u1 = PGPUID.new('UID One') u2 = PGPUID.new('UID Two') k = PGPKey.new(PubKeyAlgorithm.RSAEncryptOrSign, 512) flags = {KeyFlags.Certify, KeyFlags.Sign, KeyFlags.EncryptCommunications, KeyFlags.EncryptStorage} k.add_uid(u1, usage=flags, hashes=[HashAlgorithm.SHA1], ciphers=[SymmetricKeyAlgorithm.AES128]) k.add_uid(u2, usage=flags, hashes=[HashAlgorithm.SHA1], ciphers=[SymmetricKeyAlgorithm.Camellia128]) emsg = k.pubkey.encrypt(PGPMessage.new('This message is about to be encrypted'), user='******') # assert that it was encrypted with Camellia128 and that we can decrypt it normally assert emsg._sessionkeys[0].decrypt_sk(k._key)[0] == SymmetricKeyAlgorithm.Camellia128 assert k.decrypt(emsg).message == 'This message is about to be encrypted'
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 _encrypt_keycode(keycode, public_key): """ Encrypts a keycode with a public key :param keycode :param public_key :return: The encrypted keycode """ key_pair = pgpy.PGPKey.from_blob(public_key)[0] # https://github.com/SecurityInnovation/PGPy/issues/257 # PGPY requires KeyFlags.EncryptCommunications and KeyFlags.EncryptStorage for public key to encrypt # which we are not setting in our current APIs # the following code injects the require attributes to the public key signature to bypass PGPY check user = None if key_pair.is_primary: if user is not None: user = key_pair.get_uid(user) else: user = next(iter(key_pair.userids)) if user is not None: user.selfsig._signature.subpackets.addnew( 'KeyFlags', hashed=True, flags={KeyFlags.EncryptCommunications, KeyFlags.EncryptStorage}) user.selfsig._signature.subpackets[ 'h_KeyFlags'] = user.selfsig._signature.subpackets['KeyFlags'][0] user.selfsig._signature.subpackets.addnew('PreferredHashAlgorithms', hashed=True, flags=[HashAlgorithm.SHA256]) user.selfsig._signature.subpackets.addnew( 'PreferredSymmetricAlgorithms', hashed=True, flags=[SymmetricKeyAlgorithm.AES256]) user.selfsig._signature.subpackets.addnew( 'PreferredCompressionAlgorithms', hashed=True, flags=[CompressionAlgorithm.Uncompressed]) message = PGPMessage.new(keycode, compression=CompressionAlgorithm.Uncompressed, cipher=SymmetricKeyAlgorithm.AES256, hash=HashAlgorithm.SHA256) cipher_message = key_pair.encrypt(message) return str(cipher_message)
def encrypt(self, key): """ Encrypts the DecryptedBody for the given client's key and sets it as the Body of this message. Parameters ---------- key: pgpy.PGPKey An unlocked PGPKey Returns ------- msg: String The encrypted message """ m = key.encrypt(PGPMessage.new(self.DecryptedBody)) self.Body = str(m) return self.Body
def _encrypt_file_part(file, server_secret, client_secret, path=True): """ Encrypts a given file part for uploading to SendSafely. :param file: The path of the file (as a String) or a file as bytes. Set path param to False if using bytes. :param server_secret: The server secret, may be obtained through using SendSafely.get_package_information(package_id) :param client_secret: The client_secret (a.k.a. keycode) used to ensure only the holders of the link are able to decrypt. :return: The encrypted file (as bytes) """ passphrase = server_secret + client_secret message = PGPMessage.new(file=path, message=file, compression=CompressionAlgorithm.Uncompressed) cipher_message = message.encrypt(passphrase=passphrase, cipher=SymmetricKeyAlgorithm.AES256, hash=HashAlgorithm.SHA256) return cipher_message.__bytes__()
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
def test_encrypt_passphrase_2(self): mtxt = "This message is to be encrypted" msg = PGPMessage.new(mtxt) assert not msg.is_encrypted sk = SymmetricKeyAlgorithm.AES256.gen_key() encmsg = msg.encrypt("QwertyUiop", sessionkey=sk).encrypt("AsdfGhjkl", sessionkey=sk) assert isinstance(encmsg, PGPMessage) assert encmsg.is_encrypted assert encmsg.type == 'encrypted' # decrypt with PGPy only, since GnuPG can't do multiple passphrases for passwd in ["QwertyUiop", "AsdfGhjkl"]: decmsg = encmsg.decrypt(passwd) assert isinstance(decmsg, PGPMessage) assert decmsg.type == msg.type assert decmsg.is_compressed assert decmsg.message == mtxt
def encrypt(self, data, recipients): assert len(recipients) >= 1 clear_msg = PGPMessage.new(data) # enc_msg |= self.pgpykey.sign(enc_msg) if len(recipients) == 1: key = self._get_key_from_keyhandle(recipients[0]) enc_msg = key.pubkey.encrypt(clear_msg) else: # The symmetric cipher should be specified, in case the first # preferred cipher is not the same for all recipients public # keys. cipher = SymmetricKeyAlgorithm.AES256 sessionkey = cipher.gen_key() enc_msg = clear_msg for r in recipients: key = self._get_key_from_keyhandle(r) enc_msg = key.pubkey.encrypt(enc_msg, cipher=cipher, sessionkey=sessionkey) del sessionkey return str(enc_msg)
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(self, comp_alg): mtxt = "This message is to be encrypted" msg = PGPMessage.new(mtxt, compression=comp_alg) assert not msg.is_encrypted encmsg = msg.encrypt("QwertyUiop") assert isinstance(encmsg, PGPMessage) 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 == msg.is_compressed assert decmsg.message == mtxt assert decmsg._compression == msg._compression # decrypt with GPG via python-gnupg assert self.gpg_decrypt(encmsg, 'QwertyUiop').decode('utf-8') == decmsg.message
def ctmessage(): return PGPMessage.new("This is a cleartext message!", cleartext=True)
def test_decrypt_protected_key(self, rsa_enc, rsa_pub): emsg = rsa_pub.encrypt(PGPMessage.new("asdf")) with pytest.raises(PGPError): rsa_enc.decrypt(emsg)
def test_encrypt_insecure_cipher(self): msg = PGPMessage.new('asdf') with pytest.raises(PGPInsecureCipher): msg.encrypt('QwertyUiop', cipher=SymmetricKeyAlgorithm.IDEA)
def message(): return PGPMessage.new("This is a message!", compression=CompressionAlgorithm.Uncompressed)
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_verify_nosigs(self, rsa_sec): msg = PGPMessage.new('tests/testdata/lit') with pytest.raises(PGPError): rsa_sec.verify(msg)
def test_encrypt_sessionkey_wrongtype(self): msg = PGPMessage.new('asdf') with pytest.raises(TypeError): msg.encrypt('asdf', sessionkey=bytearray(b'asdf1234asdf1234'), cipher=SymmetricKeyAlgorithm.AES128)
def test_sign_bad_prefs(self, rsa_sec, recwarn): rsa_sec.subkeys['2A834D8E5918E886'].sign(PGPMessage.new('asdf'), hash=HashAlgorithm.RIPEMD160) w = recwarn.pop(UserWarning) assert str(w.message) == "Selected hash algorithm not in key preferences" assert w.filename == __file__
def test_encrypt_unsupported_algorithm(self): lit = PGPMessage.new('tests/testdata/lit') with pytest.raises(PGPEncryptionError): lit.encrypt("QwertyUiop", cipher=SymmetricKeyAlgorithm.Twofish256)