text: # coding: utf-8
  from __future__ import unicode_literals, division, absolute_import, print_function
  
  import os
  import re
  from ctypes import CDLL, c_void_p, c_char_p, c_int, c_ulong, c_uint, c_long, c_size_t, POINTER
  from ctypes.util import find_library
  
  from ._errors import pretty_message
  from ._ffi import LibraryNotFoundError, FFIEngineError
  
  __all__ = [
      'libcrypto',
      'version',
      'version_info',
  ]
  
  
  if os.uname().sysname == 'Darwin':
      libcrypto_path = os.path.abspath(os.path.join(os.path.dirname(__file__), "libcrypto.dylib"))
      libcrypto = CDLL(libcrypto_path, use_errno=True)
  
  elif os.uname().sysname == 'Linux':
      libcrypto_path = os.path.abspath(os.path.join(os.path.dirname(__file__), "libcrypto.so"))
  else:
      raise LibraryNotFoundError('Unsupported system')
  
  libcrypto = CDLL(libcrypto_path, use_errno=True)
  
  try:
      libcrypto.OpenSSL_version.argtypes = [c_int]
      libcrypto.OpenSSL_version.restype = c_char_p
  except (AttributeError):
      raise FFIEngineError('Error accessing libcrypto.SSLeay_version')
  
  version_string = libcrypto.OpenSSL_version(0).decode('utf-8')
  version_match = re.search('\\b(\\d\\.\\d\\.\\d[a-z]*)\\b', version_string)
  if not version_match:
      raise LibraryNotFoundError('Error detecting the version of libcrypto')
  
  version = version_match.group(1)
  version_parts = re.sub('(\\d)([a-z]+)', '\\1.\\2', version).split('.')
  version_info = tuple(int(part) if part.isdigit() else part for part in version_parts)
  
  if version_info < (0, 9, 8):
      raise LibraryNotFoundError(pretty_message(
          '''
          OpenSSL versions older than 0.9.8 are not supported - found version %s
          ''',
          version
      ))
  
  P_EVP_CIPHER_CTX = c_void_p
  P_EVP_CIPHER = c_void_p
  
  P_EVP_MD_CTX = c_void_p
  P_EVP_MD = c_void_p
  
  P_ENGINE = c_void_p
  
  P_EVP_PKEY = c_void_p
  EVP_PKEY_CTX = c_void_p
  P_EVP_PKEY_CTX = POINTER(c_void_p)
  P_X509 = POINTER(c_void_p)
  P_DH = c_void_p
  P_RSA = c_void_p
  P_DSA = c_void_p
  P_EC_KEY = c_void_p
  P_BN_GENCB = c_void_p
  BIGNUM = c_void_p
  P_BIGNUM = POINTER(BIGNUM)
  
  p_int = POINTER(c_int)
  p_uint = POINTER(c_uint)
  
  try:
  
      libcrypto.ERR_get_error.argtypes = []
      libcrypto.ERR_get_error.restype = c_ulong
  
      libcrypto.ERR_peek_error.argtypes = []
      libcrypto.ERR_peek_error.restype = c_ulong
  
      libcrypto.ERR_error_string.argtypes = [
          c_ulong,
          c_char_p
      ]
      libcrypto.ERR_error_string.restype = c_char_p
  
  
      libcrypto.OPENSSL_config.argtypes = [
          c_char_p
      ]
      libcrypto.OPENSSL_config.restype = None
  
      # This allocates the memory and inits
      libcrypto.EVP_CIPHER_CTX_new.argtype = []
      libcrypto.EVP_CIPHER_CTX_new.restype = P_EVP_CIPHER_CTX
  
      libcrypto.EVP_CIPHER_CTX_set_key_length.argtypes = [
          P_EVP_CIPHER_CTX,
          c_int
      ]
      libcrypto.EVP_CIPHER_CTX_set_key_length.restype = c_int
  
      libcrypto.EVP_CIPHER_CTX_set_padding.argtypes = [
          P_EVP_CIPHER_CTX,
          c_int
      ]
      libcrypto.EVP_CIPHER_CTX_set_padding.restype = c_int
  
      libcrypto.EVP_CIPHER_CTX_ctrl.argtypes = [
          P_EVP_CIPHER_CTX,
          c_int,
          c_int,
          c_void_p
      ]
      libcrypto.EVP_CIPHER_CTX_ctrl.restype = c_int
  
      # This cleans up and frees
      libcrypto.EVP_CIPHER_CTX_free.argtypes = [
          P_EVP_CIPHER_CTX
      ]
      libcrypto.EVP_CIPHER_CTX_free.restype = None
  
      libcrypto.EVP_get_cipherbyname.argtypes = [
          c_char_p
      ]
      libcrypto.EVP_get_cipherbyname.restype = P_EVP_CIPHER
  
  
      libcrypto.EVP_CIPHER_block_size.argtypes = [
          P_EVP_CIPHER
      ]
      libcrypto.EVP_CIPHER_block_size.restype = c_int
  
      libcrypto.EVP_CIPHER_key_length.argtypes = [
          P_EVP_CIPHER
      ]
      libcrypto.EVP_CIPHER_key_length.restype = c_int
  
      libcrypto.EVP_CIPHER_iv_length.argtypes = [
          P_EVP_CIPHER
      ]
      libcrypto.EVP_CIPHER_iv_length.restype = c_int
  
      libcrypto.EVP_CIPHER_CTX_block_size.argtypes = [
          P_EVP_CIPHER_CTX
      ]
      libcrypto.EVP_CIPHER_CTX_block_size.restype = c_int
  
      libcrypto.EVP_CIPHER_CTX_key_length.argtypes = [
          P_EVP_CIPHER_CTX
      ]
      libcrypto.EVP_CIPHER_CTX_key_length.restype = c_int
  
      libcrypto.EVP_CIPHER_CTX_iv_length.argtypes = [
          P_EVP_CIPHER_CTX
      ]
      libcrypto.EVP_CIPHER_CTX_iv_length.restype = c_int
  
      libcrypto.EVP_CipherInit_ex.argtypes = [
          P_EVP_CIPHER_CTX,
          P_EVP_CIPHER,
          P_ENGINE,
          c_char_p,
          c_char_p,
          c_int,
      ]
      libcrypto.EVP_CipherInit_ex.restype = c_int
  
      libcrypto.EVP_CipherUpdate.argtypes = [
          P_EVP_CIPHER_CTX,
          c_char_p,
          p_int,
          c_char_p,
          c_int
      ]
      libcrypto.EVP_CipherUpdate.restype = c_int
  
      libcrypto.EVP_CipherFinal_ex.argtypes = [
          P_EVP_CIPHER_CTX,
          c_char_p,
          p_int
      ]
      libcrypto.EVP_CipherFinal_ex.restype = c_int
  
  
      libcrypto.EVP_EncryptInit_ex.argtypes = [
          P_EVP_CIPHER_CTX,
          P_EVP_CIPHER,
          P_ENGINE,
          c_char_p,
          c_char_p
      ]
      libcrypto.EVP_EncryptInit_ex.restype = c_int
  
      libcrypto.EVP_EncryptUpdate.argtypes = [
          P_EVP_CIPHER_CTX,
          c_char_p,
          p_int,
          c_char_p,
          c_int
      ]
      libcrypto.EVP_EncryptUpdate.restype = c_int
  
      libcrypto.EVP_EncryptFinal_ex.argtypes = [
          P_EVP_CIPHER_CTX,
          c_char_p,
          p_int
      ]
      libcrypto.EVP_EncryptFinal_ex.restype = c_int
  
      libcrypto.EVP_DecryptInit_ex.argtypes = [
          P_EVP_CIPHER_CTX,
          P_EVP_CIPHER,
          P_ENGINE,
          c_char_p,
          c_char_p
      ]
      libcrypto.EVP_DecryptInit_ex.restype = c_int
  
      libcrypto.EVP_DecryptUpdate.argtypes = [
          P_EVP_CIPHER_CTX,
          c_char_p,
          p_int,
          c_char_p,
          c_int
      ]
      libcrypto.EVP_DecryptUpdate.restype = c_int
  
      libcrypto.EVP_DecryptFinal_ex.argtypes = [
          P_EVP_CIPHER_CTX,
          c_char_p,
          p_int
      ]
      libcrypto.EVP_DecryptFinal_ex.restype = c_int
  
      libcrypto.d2i_AutoPrivateKey.argtypes = [
          POINTER(P_EVP_PKEY),
          POINTER(c_char_p),
          c_int
      ]
      libcrypto.d2i_AutoPrivateKey.restype = P_EVP_PKEY
  
      libcrypto.d2i_PUBKEY.argtypes = [
          POINTER(P_EVP_PKEY),
          POINTER(c_char_p),
          c_int
      ]
      libcrypto.d2i_PUBKEY.restype = P_EVP_PKEY
  
      libcrypto.d2i_X509.argtypes = [
          POINTER(P_X509),
          POINTER(c_char_p),
          c_int
      ]
      libcrypto.d2i_X509.restype = P_X509
  
      libcrypto.i2d_X509.argtypes = [
          P_X509,
          POINTER(c_char_p)
      ]
      libcrypto.i2d_X509.restype = c_int
  
      libcrypto.X509_get_pubkey.argtypes = [
          P_X509
      ]
      libcrypto.X509_get_pubkey.restype = P_EVP_PKEY
  
      libcrypto.X509_free.argtypes = [
          P_X509
      ]
      libcrypto.X509_free.restype = None
  
      libcrypto.EVP_PKEY_free.argtypes = [
          P_EVP_PKEY
      ]
      libcrypto.EVP_PKEY_free.restype = None
  
  
  
  
      libcrypto.EVP_md5.argtypes = []
      libcrypto.EVP_md5.restype = P_EVP_MD
  
      libcrypto.EVP_sha1.argtypes = []
      libcrypto.EVP_sha1.restype = P_EVP_MD
  
      libcrypto.EVP_sha224.argtypes = []
      libcrypto.EVP_sha224.restype = P_EVP_MD
  
      libcrypto.EVP_sha256.argtypes = []
      libcrypto.EVP_sha256.restype = P_EVP_MD
  
      libcrypto.EVP_sha384.argtypes = []
      libcrypto.EVP_sha384.restype = P_EVP_MD
  
      libcrypto.EVP_sha512.argtypes = []
      libcrypto.EVP_sha512.restype = P_EVP_MD
  
      libcrypto.EVP_PKEY_size.argtypes = [
          P_EVP_PKEY
      ]
      libcrypto.EVP_PKEY_size.restype = c_int
  
      libcrypto.EVP_PKEY_get1_RSA.argtypes = [
          P_EVP_PKEY
      ]
      libcrypto.EVP_PKEY_get1_RSA.restype = P_RSA
  
      libcrypto.RSA_free.argtypes = [
          P_RSA
      ]
      libcrypto.RSA_free.restype = None
  
      libcrypto.RSA_public_encrypt.argtypes = [
          c_int,
          c_char_p,
          c_char_p,
          P_RSA,
          c_int
      ]
      libcrypto.RSA_public_encrypt.restype = c_int
  
      libcrypto.RSA_private_encrypt.argtypes = [
          c_int,
          c_char_p,
          c_char_p,
          P_RSA,
          c_int
      ]
      libcrypto.RSA_private_encrypt.restype = c_int
  
      libcrypto.RSA_public_decrypt.argtypes = [
          c_int,
          c_char_p,
          c_char_p,
          P_RSA,
          c_int
      ]
      libcrypto.RSA_public_decrypt.restype = c_int
  
      libcrypto.RSA_private_decrypt.argtypes = [
          c_int,
          c_char_p,
          c_char_p,
          P_RSA,
          c_int
      ]
      libcrypto.RSA_private_decrypt.restype = c_int
  
      libcrypto.EVP_DigestUpdate.argtypes = [
          P_EVP_MD_CTX,
          c_char_p,
          c_uint
      ]
      libcrypto.EVP_DigestUpdate.restype = c_int
  
      libcrypto.PKCS12_key_gen_uni.argtypes = [
          c_char_p,
          c_int,
          c_char_p,
          c_int,
          c_int,
          c_int,
          c_int,
          c_char_p,
          c_void_p
      ]
      libcrypto.PKCS12_key_gen_uni.restype = c_int
  
      libcrypto.BN_free.argtypes = [
          P_BIGNUM
      ]
      libcrypto.BN_free.restype = None
  
      libcrypto.BN_dec2bn.argtypes = [
          POINTER(P_BIGNUM),
          c_char_p
      ]
      libcrypto.BN_dec2bn.restype = c_int
  
      libcrypto.DH_new.argtypes = []
      libcrypto.DH_new.restype = P_DH
  
      libcrypto.DH_generate_parameters_ex.argtypes = [
          P_DH,
          c_int,
          c_int,
          P_BN_GENCB
      ]
      libcrypto.DH_generate_parameters_ex.restype = c_int
  
      libcrypto.i2d_DHparams.argtypes = [
          P_DH,
          POINTER(c_char_p)
      ]
      libcrypto.i2d_DHparams.restype = c_int
  
      libcrypto.DH_free.argtypes = [
          P_DH
      ]
      libcrypto.DH_free.restype = None
  
      libcrypto.RSA_new.argtypes = []
      libcrypto.RSA_new.restype = P_RSA
  
      libcrypto.RSA_generate_key_ex.argtypes = [
          P_RSA,
          c_int,
          P_BIGNUM,
          P_BN_GENCB
      ]
      libcrypto.RSA_generate_key_ex.restype = c_int
  
      libcrypto.i2d_RSAPublicKey.argtypes = [
          P_RSA,
          POINTER(c_char_p)
      ]
      libcrypto.i2d_RSAPublicKey.restype = c_int
  
      libcrypto.i2d_RSAPrivateKey.argtypes = [
          P_RSA,
          POINTER(c_char_p)
      ]
      libcrypto.i2d_RSAPrivateKey.restype = c_int
  
      libcrypto.RSA_free.argtypes = [
          P_RSA
      ]
      libcrypto.RSA_free.restype = None
  
      libcrypto.DSA_new.argtypes = []
      libcrypto.DSA_new.restype = P_DSA
  
      libcrypto.DSA_generate_parameters_ex.argtypes = [
          P_DSA,
          c_int,
          c_char_p,
          c_int,
          POINTER(c_int),
          POINTER(c_ulong),
          P_BN_GENCB
      ]
      libcrypto.DSA_generate_parameters_ex.restype = c_int
  
      libcrypto.DSA_generate_key.argtypes = [
          P_DSA
      ]
      libcrypto.DSA_generate_key.restype = c_int
  
      libcrypto.i2d_DSA_PUBKEY.argtypes = [
          P_DSA,
          POINTER(c_char_p)
      ]
      libcrypto.i2d_DSA_PUBKEY.restype = c_int
  
      libcrypto.i2d_DSAPrivateKey.argtypes = [
          P_DSA,
          POINTER(c_char_p)
      ]
      libcrypto.i2d_DSAPrivateKey.restype = c_int
  
      libcrypto.DSA_free.argtypes = [
          P_DSA
      ]
      libcrypto.DSA_free.restype = None
  
      libcrypto.EC_KEY_new_by_curve_name.argtypes = [
          c_int
      ]
      libcrypto.EC_KEY_new_by_curve_name.restype = P_EC_KEY
  
      libcrypto.EC_KEY_generate_key.argtypes = [
          P_EC_KEY
      ]
      libcrypto.EC_KEY_generate_key.restype = c_int
  
      libcrypto.EC_KEY_set_asn1_flag.argtypes = [
          P_EC_KEY,
          c_int
      ]
      libcrypto.EC_KEY_set_asn1_flag.restype = None
  
      libcrypto.i2d_ECPrivateKey.argtypes = [
          P_EC_KEY,
          POINTER(c_char_p)
      ]
      libcrypto.i2d_ECPrivateKey.restype = c_int
  
      libcrypto.i2o_ECPublicKey.argtypes = [
          P_EC_KEY,
          POINTER(c_char_p)
      ]
      libcrypto.i2o_ECPublicKey.restype = c_int
  
      libcrypto.EC_KEY_free.argtypes = [
          P_EC_KEY
      ]
      libcrypto.EC_KEY_free.restype = None
  
      if version_info < (1,):
          P_DSA_SIG = c_void_p
          P_ECDSA_SIG = c_void_p
  
          libcrypto.DSA_do_sign.argtypes = [
              c_char_p,
              c_int,
              P_DSA
          ]
          libcrypto.DSA_do_sign.restype = P_DSA_SIG
  
          libcrypto.ECDSA_do_sign.argtypes = [
              c_char_p,
              c_int,
              P_EC_KEY
          ]
          libcrypto.ECDSA_do_sign.restype = P_ECDSA_SIG
  
          libcrypto.d2i_DSA_SIG.argtypes = [
              POINTER(P_DSA_SIG),
              POINTER(c_char_p),
              c_long
          ]
          libcrypto.d2i_DSA_SIG.restype = P_DSA_SIG
  
          libcrypto.d2i_ECDSA_SIG.argtypes = [
              POINTER(P_ECDSA_SIG),
              POINTER(c_char_p),
              c_long
          ]
          libcrypto.d2i_ECDSA_SIG.restype = P_ECDSA_SIG
  
          libcrypto.i2d_DSA_SIG.argtypes = [
              P_DSA_SIG,
              POINTER(c_char_p)
          ]
          libcrypto.i2d_DSA_SIG.restype = c_int
  
          libcrypto.i2d_ECDSA_SIG.argtypes = [
              P_ECDSA_SIG,
              POINTER(c_char_p)
          ]
          libcrypto.i2d_ECDSA_SIG.restype = c_int
  
          libcrypto.DSA_do_verify.argtypes = [
              c_char_p,
              c_int,
              P_DSA_SIG,
              P_DSA
          ]
          libcrypto.DSA_do_verify.restype = c_int
  
          libcrypto.ECDSA_do_verify.argtypes = [
              c_char_p,
              c_int,
              P_ECDSA_SIG,
              P_EC_KEY
          ]
          libcrypto.ECDSA_do_verify.restype = c_int
  
          libcrypto.DSA_SIG_free.argtypes = [
              P_DSA_SIG
          ]
          libcrypto.DSA_SIG_free.restype = None
  
          libcrypto.ECDSA_SIG_free.argtypes = [
              P_ECDSA_SIG
          ]
          libcrypto.ECDSA_SIG_free.restype = None
  
          libcrypto.EVP_PKEY_get1_DSA.argtypes = [
              P_EVP_PKEY
          ]
          libcrypto.EVP_PKEY_get1_DSA.restype = P_DSA
  
          libcrypto.EVP_PKEY_get1_EC_KEY.argtypes = [
              P_EVP_PKEY
          ]
          libcrypto.EVP_PKEY_get1_EC_KEY.restype = P_EC_KEY
  
          libcrypto.RSA_verify_PKCS1_PSS.argtypes = [
              P_RSA,
              c_char_p,
              P_EVP_MD,
              c_char_p,
              c_int
          ]
          libcrypto.RSA_verify_PKCS1_PSS.restype = c_int
  
          libcrypto.RSA_padding_add_PKCS1_PSS.argtypes = [
              P_RSA,
              c_char_p,
              c_char_p,
              P_EVP_MD,
              c_int
          ]
          libcrypto.RSA_padding_add_PKCS1_PSS.restype = c_int
  
          libcrypto.EVP_DigestInit_ex.argtypes = [
              P_EVP_MD_CTX,
              P_EVP_MD,
              P_ENGINE
          ]
          libcrypto.EVP_DigestInit_ex.restype = c_int
  
          libcrypto.EVP_SignFinal.argtypes = [
              P_EVP_MD_CTX,
              c_char_p,
              p_uint,
              P_EVP_PKEY
          ]
          libcrypto.EVP_SignFinal.restype = c_int
  
          libcrypto.EVP_VerifyFinal.argtypes = [
              P_EVP_MD_CTX,
              c_char_p,
              c_uint,
              P_EVP_PKEY
          ]
          libcrypto.EVP_VerifyFinal.restype = c_int
  
          libcrypto.EVP_MD_CTX_set_flags.argtypes = [
              P_EVP_MD_CTX,
              c_int
          ]
          libcrypto.EVP_MD_CTX_set_flags.restype = None
  
      else:
          libcrypto.PKCS5_PBKDF2_HMAC.argtypes = [
              c_char_p,
              c_int,
              c_char_p,
              c_int,
              c_int,
              P_EVP_MD,
              c_int,
              c_char_p
          ]
          libcrypto.PKCS5_PBKDF2_HMAC.restype = c_int
  
          libcrypto.EVP_DigestSignInit.argtypes = [
              P_EVP_MD_CTX,
              POINTER(P_EVP_PKEY_CTX),
              P_EVP_MD,
              P_ENGINE,
              P_EVP_PKEY
          ]
          libcrypto.EVP_DigestSignInit.restype = c_int
  
          libcrypto.EVP_DigestSignFinal.argtypes = [
              P_EVP_MD_CTX,
              c_char_p,
              POINTER(c_size_t)
          ]
          libcrypto.EVP_DigestSignFinal.restype = c_int
  
          libcrypto.EVP_DigestVerifyInit.argtypes = [
              P_EVP_MD_CTX,
              POINTER(P_EVP_PKEY_CTX),
              P_EVP_MD,
              P_ENGINE,
              P_EVP_PKEY
          ]
          libcrypto.EVP_DigestVerifyInit.restype = c_int
  
          libcrypto.EVP_DigestVerifyFinal.argtypes = [
              P_EVP_MD_CTX,
              c_char_p,
              c_size_t
          ]
          libcrypto.EVP_DigestVerifyFinal.restype = c_int
  
          libcrypto.EVP_PKEY_CTX_ctrl.argtypes = [
              P_EVP_PKEY_CTX,
              c_int,
              c_int,
              c_int,
              c_int,
              c_void_p
          ]
          libcrypto.EVP_PKEY_CTX_ctrl.restype = c_int
  
  
  
  
  except (AttributeError):
      raise FFIEngineError('Error initializing ctypes')
  
  
  setattr(libcrypto, 'EVP_PKEY_CTX', EVP_PKEY_CTX)
  setattr(libcrypto, 'BIGNUM', BIGNUM)
  