diff --git a/libpkpass/crypto.py b/libpkpass/crypto.py index d67fc32..a019d70 100755 --- a/libpkpass/crypto.py +++ b/libpkpass/crypto.py @@ -5,7 +5,7 @@ import os import hashlib import shutil -from subprocess import Popen, PIPE, STDOUT +from subprocess import Popen, PIPE, STDOUT, DEVNULL from cryptography.fernet import Fernet, InvalidToken from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives import hashes @@ -13,6 +13,14 @@ from libpkpass.util import color_prepare from libpkpass.errors import EncryptionError, DecryptionError, SignatureCreationError, X509CertificateError + ############################################################################## +def handle_python_strings(string): + """handles py2/3 incompatiblities""" + ############################################################################## + if not isinstance(string, bytes): + string = string.encode("ASCII") + return string + ############################################################################## def pk_encrypt_string(plaintext_string, identity): """ Encrypt and return a base 64 encoded string for the provided identity""" @@ -29,9 +37,9 @@ def pk_encrypt_string(plaintext_string, identity): ciphertext_derived_key = stdout fern = Fernet(plaintext_derived_key) - encrypted_string = fern.encrypt(plaintext_string.encode("ASCII")) + encrypted_string = fern.encrypt(handle_python_strings(plaintext_string)) - return (encrypted_string, base64.urlsafe_b64encode(ciphertext_derived_key)) + return (encrypted_string, base64.urlsafe_b64encode(handle_python_strings(ciphertext_derived_key))) ############################################################################## def print_card_info(card_slot, identity, verbosity, color, theme_map): @@ -41,7 +49,7 @@ def print_card_info(card_slot, identity, verbosity, color, theme_map): command = ['pkcs11-tool', '-L'] proc = Popen(command, stdout=PIPE, stdin=PIPE, stderr=STDOUT) stdout, _ = proc.communicate() - out_list = stdout.split(b'Slot') + out_list = handle_python_strings(stdout).split(b'Slot') if verbosity > 1: print_all_slots(stdout, color, theme_map) for out in out_list[1:]: @@ -58,13 +66,14 @@ def print_all_slots(slot_info, color, theme_map): ############################################################################## columns = int(shutil.get_terminal_size().columns) // 4 print(color_prepare("#" * columns, "debug", color, theme_map)) - print(slot_info.decode("ASCII").strip()) + print(handle_python_strings(slot_info).decode("ASCII").strip()) print(color_prepare("#" * columns, "debug", color, theme_map)) ############################################################################## def pk_decrypt_string(ciphertext_string, ciphertext_derived_key, identity, passphrase, card_slot=None): """ Decrypt a base64 encoded string for the provided identity""" ############################################################################## + ciphertext_derived_key = handle_python_strings(ciphertext_derived_key) if 'key_path' in identity: command = ['openssl', 'rsautl', '-inkey', identity['key_path'], '-decrypt', '-pkcs'] proc = Popen(command, stdout=PIPE, stdin=PIPE, stderr=STDOUT) @@ -81,9 +90,7 @@ def pk_decrypt_string(ciphertext_string, ciphertext_derived_key, identity, passp if card_slot is not None: command.extend(['--reader', str(card_slot)]) command.extend(['--pin', '-']) - #subprocess.DEVNULL doesn't exist in python2 so... - with open(os.devnull, 'w') as devnull: - proc = Popen(command, stdout=PIPE, stdin=PIPE, stderr=devnull) + proc = Popen(command, stdout=PIPE, stdin=PIPE, stderr=DEVNULL) stdout, _ = proc.communicate(input=passphrase.encode('ASCII')) os.unlink(fname.name) try: @@ -96,7 +103,7 @@ def pk_decrypt_string(ciphertext_string, ciphertext_derived_key, identity, passp fern = Fernet(plaintext_derived_key) - plaintext_string = fern.decrypt(ciphertext_string) + plaintext_string = fern.decrypt(handle_python_strings(ciphertext_string)) return plaintext_string.decode("ASCII") ############################################################################## @@ -108,7 +115,7 @@ def pk_sign_string(string, identity, passphrase, card_slot=None): command = ['openssl', 'rsautl', '-sign', '-inkey', identity['key_path']] proc = Popen(command, stdout=PIPE, stdin=PIPE, stderr=STDOUT) stdout, _ = proc.communicate(input=stringhash.encode('ASCII')) - signature = base64.urlsafe_b64encode(stdout) + signature = base64.urlsafe_b64encode(handle_python_strings(stdout)) else: # We've got to use pkcs15-crypt for PIV cards, and it only supports pin on # command line (insecure) or via stdin. So, we have to put signature text @@ -125,7 +132,7 @@ def pk_sign_string(string, identity, passphrase, card_slot=None): out.close() with open(out.name, 'rb') as sigfile: - signature = base64.urlsafe_b64encode(sigfile.read()) + signature = base64.urlsafe_b64encode(handle_python_strings(sigfile.read())) os.unlink(fname.name) os.unlink(out.name) @@ -142,7 +149,7 @@ def pk_verify_signature(string, signature, identity): stringhash = hashlib.sha256(string.encode("ASCII")).hexdigest() command = ['openssl', 'rsautl', '-inkey', identity['certificate_path'], '-certin', '-verify'] proc = Popen(command, stdout=PIPE, stdin=PIPE, stderr=STDOUT) - stdout, _ = proc.communicate(input=base64.urlsafe_b64decode(signature)) + stdout, _ = proc.communicate(input=base64.urlsafe_b64decode(handle_python_strings(signature))) return stdout.decode("ASCII") == stringhash @@ -216,15 +223,16 @@ def sk_encrypt_string(plaintext_string, key): ############################################################################## fern = Fernet(hash_password(key)) encrypted_string = fern.encrypt(plaintext_string.encode('ASCII')) - return base64.urlsafe_b64encode(encrypted_string) + return base64.urlsafe_b64encode(handle_python_strings(encrypted_string)) ############################################################################## def sk_decrypt_string(ciphertext_string, key): """ Symmetrically Decrypt a base64 encoded string using the provided key""" ############################################################################## fern = Fernet(hash_password(key)) + ciphertext_string = handle_python_strings(ciphertext_string) try: - plaintext_string = fern.decrypt(base64.urlsafe_b64decode(ciphertext_string)) + plaintext_string = fern.decrypt(base64.urlsafe_b64decode(handle_python_strings(ciphertext_string))) return plaintext_string.decode("ASCII") except InvalidToken: # handle some legacy stuff from NCCS @@ -238,6 +246,7 @@ def sk_decrypt_string(ciphertext_string, key): def hash_password(password): """Hash people's password""" ############################################################################## + password = handle_python_strings("%s" % password) kdf = PBKDF2HMAC(algorithm=hashes.SHA256(), length=32, salt=b"salt", iterations=100000, backend=default_backend()) - return base64.urlsafe_b64encode(kdf.derive(password)) + return base64.urlsafe_b64encode(handle_python_strings(kdf.derive(password))) diff --git a/libpkpass/password.py b/libpkpass/password.py index 668ae36..05c91c8 100644 --- a/libpkpass/password.py +++ b/libpkpass/password.py @@ -208,7 +208,7 @@ def verify_entry(self, uid=None, iddb=None): identitydb = iddb.iddb recipient_entry = self.recipients[uid].copy() distributor = recipient_entry['distributor'] - iddb.verify_identity(distributor) + iddb.verify_identity(distributor, []) signature = recipient_entry.pop('signature') message = self._create_signable_string(recipient_entry) sig_ok = crypto.pk_verify_signature(