mirror of
				https://github.com/LonamiWebs/Telethon.git
				synced 2025-11-04 01:47:27 +03:00 
			
		
		
		
	
		
			
				
	
	
		
			141 lines
		
	
	
		
			4.4 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			141 lines
		
	
	
		
			4.4 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
"""
 | 
						|
Helper module around the system's libssl library if available for IGE mode.
 | 
						|
"""
 | 
						|
import ctypes
 | 
						|
import ctypes.util
 | 
						|
import platform
 | 
						|
import sys
 | 
						|
try:
 | 
						|
    import ctypes.macholib.dyld
 | 
						|
except ImportError:
 | 
						|
    pass
 | 
						|
import logging
 | 
						|
import os
 | 
						|
 | 
						|
__log__ = logging.getLogger(__name__)
 | 
						|
 | 
						|
 | 
						|
def _find_ssl_lib():
 | 
						|
    lib = ctypes.util.find_library('ssl')
 | 
						|
    # macOS 10.15 segfaults on  unversioned crypto libraries.
 | 
						|
    # We therefore pin the current stable version here
 | 
						|
    # Credit for fix goes to Sarah Harvey (@worldwise001)
 | 
						|
    # https://www.shh.sh/2020/01/04/python-abort-trap-6.html
 | 
						|
    if sys.platform == 'darwin':
 | 
						|
        release, _version_info, _machine = platform.mac_ver()
 | 
						|
        ten, major, *minor = release.split('.')
 | 
						|
        # macOS 10.14 "mojave" is the last known major release
 | 
						|
        # to support unversioned libssl.dylib. Anything above
 | 
						|
        # needs specific versions
 | 
						|
        if major and int(major) > 14:
 | 
						|
            lib = (
 | 
						|
                ctypes.util.find_library('libssl.46') or
 | 
						|
                ctypes.util.find_library('libssl.44') or
 | 
						|
                ctypes.util.find_library('libssl.42')
 | 
						|
            )
 | 
						|
    if not lib:
 | 
						|
        raise OSError('no library called "ssl" found')
 | 
						|
 | 
						|
    # First, let ctypes try to handle it itself.
 | 
						|
    try:
 | 
						|
        libssl = ctypes.cdll.LoadLibrary(lib)
 | 
						|
    except OSError:
 | 
						|
        pass
 | 
						|
    else:
 | 
						|
        return libssl
 | 
						|
 | 
						|
    # This is a best-effort attempt at finding the full real path of lib.
 | 
						|
    #
 | 
						|
    # Unfortunately ctypes doesn't tell us *where* it finds the library,
 | 
						|
    # so we have to do that ourselves.
 | 
						|
    try:
 | 
						|
        # This is not documented, so it could fail. Be on the safe side.
 | 
						|
        paths = ctypes.macholib.dyld.DEFAULT_LIBRARY_FALLBACK
 | 
						|
    except AttributeError:
 | 
						|
        paths = [
 | 
						|
            os.path.expanduser("~/lib"),
 | 
						|
            "/usr/local/lib",
 | 
						|
            "/lib",
 | 
						|
            "/usr/lib",
 | 
						|
        ]
 | 
						|
 | 
						|
    for path in paths:
 | 
						|
        if os.path.isdir(path):
 | 
						|
            for root, _, files in os.walk(path):
 | 
						|
                if lib in files:
 | 
						|
                    # Manually follow symbolic links on *nix systems.
 | 
						|
                    # Fix for https://github.com/LonamiWebs/Telethon/issues/1167
 | 
						|
                    lib = os.path.realpath(os.path.join(root, lib))
 | 
						|
                    return ctypes.cdll.LoadLibrary(lib)
 | 
						|
    else:
 | 
						|
        raise OSError('no absolute path for "%s" and cannot load by name' % lib)
 | 
						|
 | 
						|
 | 
						|
try:
 | 
						|
    _libssl = _find_ssl_lib()
 | 
						|
except OSError as e:
 | 
						|
    # See https://github.com/LonamiWebs/Telethon/issues/1167
 | 
						|
    # Sometimes `find_library` returns improper filenames.
 | 
						|
    __log__.info('Failed to load SSL library: %s (%s)', type(e), e)
 | 
						|
    _libssl = None
 | 
						|
 | 
						|
if not _libssl:
 | 
						|
    decrypt_ige = None
 | 
						|
    encrypt_ige = None
 | 
						|
else:
 | 
						|
    # https://github.com/openssl/openssl/blob/master/include/openssl/aes.h
 | 
						|
    AES_ENCRYPT = ctypes.c_int(1)
 | 
						|
    AES_DECRYPT = ctypes.c_int(0)
 | 
						|
    AES_MAXNR = 14
 | 
						|
 | 
						|
    class AES_KEY(ctypes.Structure):
 | 
						|
        """Helper class representing an AES key"""
 | 
						|
        _fields_ = [
 | 
						|
            ('rd_key', ctypes.c_uint32 * (4 * (AES_MAXNR + 1))),
 | 
						|
            ('rounds', ctypes.c_uint),
 | 
						|
        ]
 | 
						|
 | 
						|
    def decrypt_ige(cipher_text, key, iv):
 | 
						|
        aes_key = AES_KEY()
 | 
						|
        key_len = ctypes.c_int(8 * len(key))
 | 
						|
        key = (ctypes.c_ubyte * len(key))(*key)
 | 
						|
        iv = (ctypes.c_ubyte * len(iv))(*iv)
 | 
						|
 | 
						|
        in_len = ctypes.c_size_t(len(cipher_text))
 | 
						|
        in_ptr = (ctypes.c_ubyte * len(cipher_text))(*cipher_text)
 | 
						|
        out_ptr = (ctypes.c_ubyte * len(cipher_text))()
 | 
						|
 | 
						|
        _libssl.AES_set_decrypt_key(key, key_len, ctypes.byref(aes_key))
 | 
						|
        _libssl.AES_ige_encrypt(
 | 
						|
            ctypes.byref(in_ptr),
 | 
						|
            ctypes.byref(out_ptr),
 | 
						|
            in_len,
 | 
						|
            ctypes.byref(aes_key),
 | 
						|
            ctypes.byref(iv),
 | 
						|
            AES_DECRYPT
 | 
						|
        )
 | 
						|
 | 
						|
        return bytes(out_ptr)
 | 
						|
 | 
						|
    def encrypt_ige(plain_text, key, iv):
 | 
						|
        aes_key = AES_KEY()
 | 
						|
        key_len = ctypes.c_int(8 * len(key))
 | 
						|
        key = (ctypes.c_ubyte * len(key))(*key)
 | 
						|
        iv = (ctypes.c_ubyte * len(iv))(*iv)
 | 
						|
 | 
						|
        in_len = ctypes.c_size_t(len(plain_text))
 | 
						|
        in_ptr = (ctypes.c_ubyte * len(plain_text))(*plain_text)
 | 
						|
        out_ptr = (ctypes.c_ubyte * len(plain_text))()
 | 
						|
 | 
						|
        _libssl.AES_set_encrypt_key(key, key_len, ctypes.byref(aes_key))
 | 
						|
        _libssl.AES_ige_encrypt(
 | 
						|
            ctypes.byref(in_ptr),
 | 
						|
            ctypes.byref(out_ptr),
 | 
						|
            in_len,
 | 
						|
            ctypes.byref(aes_key),
 | 
						|
            ctypes.byref(iv),
 | 
						|
            AES_ENCRYPT
 | 
						|
        )
 | 
						|
 | 
						|
        return bytes(out_ptr)
 |