# Path: pysmime/util.py
# def BIO_from_buffer(data=None):
#     """
#     Returns a BIO oject for OpenSSL from input memory buffer
#     """
#     if not data or isinstance(data, bytes):
#         return BIO.MemoryBuffer(data)
#     else:
#         return BIO.MemoryBuffer(bytes(data))
# 
# def set_keyring(smime, private_key, cert, keyring_source):
#     """
#     Sets private key and certificate for input smime object based on keyring
#     source.
# 
#     @type smime: M2Crypto.SMIME
#     @param smime: the smime object to update with key and certificate data
#     @type private_key: filepath or M2Crypto.BIO or M2Crypto.EVP.PKey
#     @param private_key: private key reference, could be from file, from memory
#         or from pkcs11 smartcard, based on keyring_soruce input parameter
#     @type cert: filepath or M2Crypto.BIO or M2Crypto.X509.X509
#     @param cert: certificate, could be from filepath, from memory or from
#         pkcs11 smartcard, based on keyring_soruce input parameter
#     @type keyring_source: str
#     @keyword keyring_source: the type of the source for input certificate, used
#         to recall the appropriate method for SMIME settings. Ammitted
#         values are: file, memory, pkcs11.
#     @rtype: boolean
#     @return: True if a valid keyring source, else False
#     @raise BadKeyringSource: the selected Keyring source is not valid. Ammitted
#         values are file, memory and pkcs11.
#     """
#     if keyring_source == 'file':
#         smime.load_key(private_key, cert)
#         return True
#     elif keyring_source == 'memory':
#         smime.load_key_bio(private_key, cert)
#         return True
#     elif keyring_source == 'pkcs11':
#         smime.pkey = private_key
#         smime.x509 = cert
#         return True
#     else:
#         logging.error('unknown keyring source: ' + keyring_source +
#                       '; possible values: file, memory, pkcs11')
#         raise BadKeyringSource('unknown keyring source: ' + keyring_source +
#                                '; possible values: file, memory, pkcs11')
# 
# def set_certificate(cert, keyring_source):
#     """
#     Sets certificate for input x509 object based on keyring source.
# 
#     @type cert: filepath or M2Crypto.BIO or M2Crypto.X509.X509
#     @param cert: certificate, could be from filepath, from memory or from
#         pkcs11 smartcard, based on keyring_soruce input parameter
#     @type keyring_source: str
#     @keyword keyring_source: the type of the source for input certificate, used
#         to recall the appropriate method for X509 settings. Ammitted
#         values are: file, memory, pkcs11.
#     @rtype: M2Crypto.X509.X509 or None
#     @return: the new X509 certificate if a valid keyring source, else False
#     @raise BadKeyringSource: the selected Keyring source is not valid. Ammitted
#         values are file, memory and pkcs11.
#     """
#     if keyring_source == 'file':
#         x509 = X509.load_cert(cert)
#         return x509
#     elif keyring_source == 'memory':
#         x509 = X509.load_cert_bio(cert)
#         return x509
#     elif keyring_source == 'pkcs11':
#         x509.cert = cert
#         return x509
#     else:
#         logging.error('unknown keyring source: ' + keyring_source +
#                       '; possible values: file, memory, pkcs11')
#         raise BadKeyringSource('unknown keyring source: ' + keyring_source +
#                                '; possible values: file, memory, pkcs11')
# 
# def seed_prng():
#     """
#     Seed the pseudorandom number generator
#     """
#     sources = ['sensors_temperatures', 'users', 'virtual_memory',
#                'net_connections', 'pids', 'disk_partitions']
#     try:
#         # Python 3
#         Rand.rand_seed(bytes(''.join([str(getattr(psutil, a, str)())
#                        for a in sources]), 'utf-8'))
#     except TypeError:
#         # Python 2
#         Rand.rand_seed(str([getattr(psutil, a, str)()
#                        for a in sources]))
# 
#     return True


import os
import base64
import inspect
import logging
from M2Crypto import SMIME, X509, m2
from pysmime.util import (BIO_from_buffer, set_keyring, set_certificate,
                          seed_prng)


def encrypt(input_bio, cert, keyring_source, cypher):
    """
    Encrypts the input data with the public key in the certificate from keyring
    source with selected cypher.

    @type input_bio: M2Crypto.BIO
    @param input_bio: input data to encrypt.
    @type cert:  filepath or M2Crypto.BIO or M2Crypto.X509.X509
    @param cert: the recipient certificate reference from filepath, could be
        from file, from memory or from pkcs11 smartcard, based on
        keyring_soruce input parameter.
    @type keyring_source: str
    @keyword keyring_source: the type of the source for input certificate, used
        to recall the appropriate method for encrypter settings. Ammitted
        values are: file, memory, pkcs11.
    @type cypher: str
    @keyword cypher: the cypher to use for encryption of the data, run
        "openssl enc -help" for supported cyphers, you have to choose a public
        key cypher from availables.
    @rtype: M2Crypto.SMIME.PKCS7
    @return: the PKCS#7 encrypted data in PEM format.
    """
    encrypter = SMIME.SMIME()
    x509 = set_certificate(cert, keyring_source)
    sk = X509.X509_Stack()
    sk.push(x509)
    encrypter.set_x509_stack(sk)
    encrypter.set_cipher(SMIME.Cipher(cypher))

# Path: pysmime/util.py
# def BIO_from_buffer(data=None):
#     """
#     Returns a BIO oject for OpenSSL from input memory buffer
#     """
#     if not data or isinstance(data, bytes):
#         return BIO.MemoryBuffer(data)
#     else:
#         return BIO.MemoryBuffer(bytes(data))
# 
# def set_keyring(smime, private_key, cert, keyring_source):
#     """
#     Sets private key and certificate for input smime object based on keyring
#     source.
# 
#     @type smime: M2Crypto.SMIME
#     @param smime: the smime object to update with key and certificate data
#     @type private_key: filepath or M2Crypto.BIO or M2Crypto.EVP.PKey
#     @param private_key: private key reference, could be from file, from memory
#         or from pkcs11 smartcard, based on keyring_soruce input parameter
#     @type cert: filepath or M2Crypto.BIO or M2Crypto.X509.X509
#     @param cert: certificate, could be from filepath, from memory or from
#         pkcs11 smartcard, based on keyring_soruce input parameter
#     @type keyring_source: str
#     @keyword keyring_source: the type of the source for input certificate, used
#         to recall the appropriate method for SMIME settings. Ammitted
#         values are: file, memory, pkcs11.
#     @rtype: boolean
#     @return: True if a valid keyring source, else False
#     @raise BadKeyringSource: the selected Keyring source is not valid. Ammitted
#         values are file, memory and pkcs11.
#     """
#     if keyring_source == 'file':
#         smime.load_key(private_key, cert)
#         return True
#     elif keyring_source == 'memory':
#         smime.load_key_bio(private_key, cert)
#         return True
#     elif keyring_source == 'pkcs11':
#         smime.pkey = private_key
#         smime.x509 = cert
#         return True
#     else:
#         logging.error('unknown keyring source: ' + keyring_source +
#                       '; possible values: file, memory, pkcs11')
#         raise BadKeyringSource('unknown keyring source: ' + keyring_source +
#                                '; possible values: file, memory, pkcs11')
# 
# def set_certificate(cert, keyring_source):
#     """
#     Sets certificate for input x509 object based on keyring source.
# 
#     @type cert: filepath or M2Crypto.BIO or M2Crypto.X509.X509
#     @param cert: certificate, could be from filepath, from memory or from
#         pkcs11 smartcard, based on keyring_soruce input parameter
#     @type keyring_source: str
#     @keyword keyring_source: the type of the source for input certificate, used
#         to recall the appropriate method for X509 settings. Ammitted
#         values are: file, memory, pkcs11.
#     @rtype: M2Crypto.X509.X509 or None
#     @return: the new X509 certificate if a valid keyring source, else False
#     @raise BadKeyringSource: the selected Keyring source is not valid. Ammitted
#         values are file, memory and pkcs11.
#     """
#     if keyring_source == 'file':
#         x509 = X509.load_cert(cert)
#         return x509
#     elif keyring_source == 'memory':
#         x509 = X509.load_cert_bio(cert)
#         return x509
#     elif keyring_source == 'pkcs11':
#         x509.cert = cert
#         return x509
#     else:
#         logging.error('unknown keyring source: ' + keyring_source +
#                       '; possible values: file, memory, pkcs11')
#         raise BadKeyringSource('unknown keyring source: ' + keyring_source +
#                                '; possible values: file, memory, pkcs11')
# 
# def seed_prng():
#     """
#     Seed the pseudorandom number generator
#     """
#     sources = ['sensors_temperatures', 'users', 'virtual_memory',
#                'net_connections', 'pids', 'disk_partitions']
#     try:
#         # Python 3
#         Rand.rand_seed(bytes(''.join([str(getattr(psutil, a, str)())
#                        for a in sources]), 'utf-8'))
#     except TypeError:
#         # Python 2
#         Rand.rand_seed(str([getattr(psutil, a, str)()
#                        for a in sources]))
# 
#     return True


# Path: pysmime/core.py
import os
import base64
import inspect
import logging
from M2Crypto import SMIME, X509, m2
from pysmime.util import (BIO_from_buffer, set_keyring, set_certificate,
                          seed_prng)



def encrypt(input_bio, cert, keyring_source, cypher):
    """
    Encrypts the input data with the public key in the certificate from keyring
    source with selected cypher.

    @type input_bio: M2Crypto.BIO
    @param input_bio: input data to encrypt.
    @type cert:  filepath or M2Crypto.BIO or M2Crypto.X509.X509
    @param cert: the recipient certificate reference from filepath, could be
        from file, from memory or from pkcs11 smartcard, based on
        keyring_soruce input parameter.
    @type keyring_source: str
    @keyword keyring_source: the type of the source for input certificate, used
        to recall the appropriate method for encrypter settings. Ammitted
        values are: file, memory, pkcs11.
    @type cypher: str
    @keyword cypher: the cypher to use for encryption of the data, run
        "openssl enc -help" for supported cyphers, you have to choose a public
        key cypher from availables.
    @rtype: M2Crypto.SMIME.PKCS7
    @return: the PKCS#7 encrypted data in PEM format.
    """
    encrypter = SMIME.SMIME()
    x509 = set_certificate(cert, keyring_source)
    sk = X509.X509_Stack()
    sk.push(x509)
    encrypter.set_x509_stack(sk)
    encrypter.set_cipher(SMIME.Cipher(cypher))

    seed_prng()