Search code examples
pythonopenssl

How To Decrypt a .p7m File via Python Openssl


I have a python program, that iterates over emails and download the Attachment files. Now I want to procsess the content of said emails.

I have a key like this "c34pj34365g0394hg" and a smime_post.key file with content like this:

-----BEGIN ENCRYPTED PRIVATE KEY-----
MIIJrTBXBgkqhkiG9w0BBQ0wSjApBgkqhkiG9w0BBQwwHAQIeHcIC+7nTU4CAggA
MAwGCCqGSIb3DQIJBQAwHQYJYIZIAWUDBAEqBBC/DGRNkgo3TizIHH3TWnHqBIIJ
UPu99JJuhB6hcHYS5UxgACXAdO6xOmXV7C1JUduGmTfNin0YwkJN7SMG6nOhGuxN
6BWczg5ENf1b3btIB6LwxyCFY+O/lvgzXMWrOr6/0XEQt3p7WTqOxbZ94nEcki1u
vZT9QdtveNAoZrZ48RyY1uoo2l3GLbSumSKaHx88lGLecMtnbUhFbwfE6Z6l6msK
VIi6kq+g1qiFD62xenyyS20UHkTgPy8CsJdllDDfU+aPxkOzTmfAdEHeIUzYwNPu

and on top of that of course the smime.p7m file with the encryptet content. I'm not able to finde something usefull to this topic.

I had a similar problem with another email import (from italy) where I was able to encrypt the file with this code:

def remove_signature(fileString):
    p7 = crypto.load_pkcs7_data(crypto.FILETYPE_ASN1, fileString)
    bio_out = crypto._new_mem_buf()
    res = _lib.PKCS7_verify(p7._pkcs7, _ffi.NULL, _ffi.NULL, _ffi.NULL, bio_out,
                            _lib.PKCS7_NOVERIFY | _lib.PKCS7_NOSIGS)

    if res == 1:
        return (crypto._bio_to_string(bio_out).decode('UTF-8'))
    else:
        errno = _lib.ERR_get_error()
        errstrlib = _ffi.string(_lib.ERR_lib_error_string(errno))
        errstrfunc = _ffi.string(_lib.ERR_func_error_string(errno))
        errstrreason = _ffi.string(_lib.ERR_reason_error_string(errno))
        print(f"------------------------------------\berrstrreason: {errstrreason}---------------------------\b")
        print(f"------------------------------------\berrno: {errno}---------------------------\b")
        print(f"------------------------------------\berrstrlib: {errstrlib}---------------------------\b")
        print(f"------------------------------------\berrstrfunc: {errstrfunc}---------------------------\b")
        return ""

My guess is, that I have to decrypt the .key file and use that as a cert? If someone has some experience with that, I would appreciate any help.


Solution

  • Tock me some time, but I got my problem solved. We changed the encryption to pgp and here is how I generate my keys / encrypt / decrypt files / blobs (i.e. a mailattachment)

    import pgpy
    from pgpy.constants import PubKeyAlgorithm, KeyFlags, HashAlgorithm, SymmetricKeyAlgorithm, CompressionAlgorithm
    
     class PgpDecryptor:
        """
        A class that can encrypt / decrypt files with pgp encryption.
        """
        # in die config packen?
        filename_key = "key.pem"
    
        def __init__(self):
            self.key = None
            self.message = None
            self.encrypted_message = None
            self.filename_org = None
        self.filename_encrypted_PGPMessage = None
        self.passphrase = None
    
    def generate_pgp_key(self, filename_key, passphrase=None):
        """
        Generates a new pgp key pair with a passphrase. T
        :param filename_key: The path for the key storage
        :param passphrase: The passphrase to lock / unlock the private key
        """
        self.key = pgpy.PGPKey.new(PubKeyAlgorithm.RSAEncryptOrSign, 4096)
        uid = pgpy.PGPUID.new('Martin Kraemer', email='martin.kraemer@sixt.com')
    
        # All diese Verschluesselungstechniken / usages usw. sind moeglich (keine Preferenz)
        # Man kann ebenfalls nen expiration date mitgeben (in etwa so: key_expiration=timedelta(days=365))
        self.key.add_uid(uid, usage={KeyFlags.Sign, KeyFlags.EncryptCommunications, KeyFlags.EncryptStorage},
                         hashes=[HashAlgorithm.SHA256, HashAlgorithm.SHA384, HashAlgorithm.SHA512,
                                 HashAlgorithm.SHA224],
                         ciphers=[SymmetricKeyAlgorithm.AES256, SymmetricKeyAlgorithm.AES192,
                                  SymmetricKeyAlgorithm.AES128],
                         compression=[CompressionAlgorithm.ZLIB, CompressionAlgorithm.BZ2, CompressionAlgorithm.ZIP,
                                      CompressionAlgorithm.Uncompressed])
    
        # protect a key with a phrase like "Schnarr"
        # this phrase is needed to use the private key
        if passphrase:
            self.key.protect(passphrase, SymmetricKeyAlgorithm.AES256, HashAlgorithm.SHA256)
        save_to_file(filename_key, str(self.key), mode="w")
        save_to_file(f"pub_{filename_key}", str(self.key.pubkey), mode="w")
    
    def encrypt_file(self, file_to_encrypt=None, filename_encrypted_file=None, key_path=None):
        """
        Encrypts a file with a pgp key.
        :param file_to_encrypt: The path to the file we want to encrypt
        :param filename_encrypted_file: The path to the file we've encrypted
        :poram key_path: Sets the path to an specific key, otherwise the key in the same folder (key.pem) is used
        """
        if file_to_encrypt:
            self.filename_org = file_to_encrypt
        if filename_encrypted_file:
            self.filename_encrypted_PGPMessage = filename_encrypted_file
    
        self.__get_message()
        self.key = self.__get_pgp_key(key_path)
        self.encrypted_message = self.key.pubkey.encrypt(self.message)
        save_to_file(self.filename_encrypted_PGPMessage, str(self.encrypted_message), mode="w")
    
    def decrypt_blob(self, blob_to_decrypt, filename_decrypted_file, key_path=None, passphrase=None):
        """
        Decrypts an blob that is pgp encrypted, using the private we've already created and saves the result
        to the given file
        :param blob_to_decrypt: If set, encrypt the message directly and not from file
        :param filename_decrypted_file: The filename of the decrypted file
        :poram key_path: Sets the path to an specific key, otherwise the key in the same folder (key.pem) is used
        :poram passphrase: The passphrase used to unlock the private key
        """
        self.key = self.__get_pgp_key(key_path)
        self.message = pgpy.PGPMessage.from_blob(blob_to_decrypt)
    
        # unlock the key with the passphrase
        with self.key.unlock(passphrase) as k:
            save_to_file(filename_decrypted_file, self.key.decrypt(self.message).message, mode='wb')
    
    def decrypt_file(self, file_to_decrypt, filename_decrypted_file, key_path=None, passphrase=None):
        """
        Decrypts an blob that is pgp encrypted, using the private we've already created and saves the result
        to the given file
        :param file_to_decrypt: The file we want to decrypt (path to the file)
        :param filename_decrypted_file: The filename of the decrypted file
        :poram key_path: Sets the path to an specific key, otherwise the key in the same folder (key.pem) is used
        :poram passphrase: The passphrase used to unlock the private key
        """
        self.key = self.__get_pgp_key(key_path)
        self.message = pgpy.PGPMessage.from_file(file_to_decrypt)
    
        # unlock the key with the passphrase
        with self.key.unlock(passphrase) as k:
            save_to_file(filename_decrypted_file, self.key.decrypt(self.message).message, mode='wb')
    
    
    def __get_pgp_key(self, key_path=None):
        if key_path:
            key, _ = pgpy.PGPKey.from_file(key_path)
        else:
            key, _ = pgpy.PGPKey.from_file(self.filename_key)
        return key
    
    def __get_message(self):
        with open(self.filename_org, "rb") as f:
            self.message = pgpy.PGPMessage.new(f.read())
    
    
    def save_to_file(file_name, content, path=".", mode='wb'):
        with open(f"{path}/{file_name}", mode=mode) as f:
            if mode.startswith('w'):
                f.write(content)
            else:
                f.append(content)
    

    and here is how to use it:

    # encrypt example:
    pgp_decryptor = PgpDecryptor()
    pgp_decryptor.generate_pgp_key(filename_key="test.pem")
    # pgp_decryptor.generate_pgp_key(filename_key="test.pem", passphrase="schnarr")
    pgp_decryptor.encrypt_file(file_to_encrypt="43630766.PDF", filename_encrypted_file="43630766_encrypted.pdf", key_path="test.pem")
    pgp_decryptor.decrypt_file("43630766_encrypted.pdf", "43630766_decrypted.pdf", key_path="test.pem")
    # pgp_decryptor.decrypt_file("43630766_encrypted.pdf", "43630766_decrypted.pdf", key_path="test.pem", passphrase="schnarr")