From 030f29220328693e08bc9bc7148b07ddc22f7aef Mon Sep 17 00:00:00 2001 From: Lonami Exo Date: Fri, 16 Feb 2018 18:24:44 +0100 Subject: [PATCH] Dump libssl bindings in favour of the new optional cryptg module --- telethon/crypto/aes.py | 124 ++++++++++++++++++++------------------ telethon/crypto/libssl.py | 107 -------------------------------- 2 files changed, 64 insertions(+), 167 deletions(-) delete mode 100644 telethon/crypto/libssl.py diff --git a/telethon/crypto/aes.py b/telethon/crypto/aes.py index 191cde15..8f13b5f0 100644 --- a/telethon/crypto/aes.py +++ b/telethon/crypto/aes.py @@ -3,86 +3,90 @@ AES IGE implementation in Python. This module may use libssl if available. """ import os import pyaes -from . import libssl + +try: + import cryptg +except ImportError: + cryptg = None -if libssl.AES is not None: - # Use libssl if available, since it will be faster - AES = libssl.AES -else: - # Fallback to a pure Python implementation - class AES: +class AES: + """ + Class that servers as an interface to encrypt and decrypt + text through the AES IGE mode. + """ + @staticmethod + def decrypt_ige(cipher_text, key, iv): """ - Class that servers as an interface to encrypt and decrypt - text through the AES IGE mode. + Decrypts the given text in 16-bytes blocks by using the + given key and 32-bytes initialization vector. """ - @staticmethod - def decrypt_ige(cipher_text, key, iv): - """ - Decrypts the given text in 16-bytes blocks by using the - given key and 32-bytes initialization vector. - """ - iv1 = iv[:len(iv) // 2] - iv2 = iv[len(iv) // 2:] + if cryptg: + return cryptg.decrypt_ige(cipher_text, key, iv) - aes = pyaes.AES(key) + iv1 = iv[:len(iv) // 2] + iv2 = iv[len(iv) // 2:] - plain_text = [] - blocks_count = len(cipher_text) // 16 + aes = pyaes.AES(key) - cipher_text_block = [0] * 16 - for block_index in range(blocks_count): - for i in range(16): - cipher_text_block[i] = \ - cipher_text[block_index * 16 + i] ^ iv2[i] + plain_text = [] + blocks_count = len(cipher_text) // 16 - plain_text_block = aes.decrypt(cipher_text_block) + cipher_text_block = [0] * 16 + for block_index in range(blocks_count): + for i in range(16): + cipher_text_block[i] = \ + cipher_text[block_index * 16 + i] ^ iv2[i] - for i in range(16): - plain_text_block[i] ^= iv1[i] + plain_text_block = aes.decrypt(cipher_text_block) - iv1 = cipher_text[block_index * 16:block_index * 16 + 16] - iv2 = plain_text_block + for i in range(16): + plain_text_block[i] ^= iv1[i] - plain_text.extend(plain_text_block) + iv1 = cipher_text[block_index * 16:block_index * 16 + 16] + iv2 = plain_text_block - return bytes(plain_text) + plain_text.extend(plain_text_block) - @staticmethod - def encrypt_ige(plain_text, key, iv): - """ - Encrypts the given text in 16-bytes blocks by using the - given key and 32-bytes initialization vector. - """ + return bytes(plain_text) - # Add random padding iff it's not evenly divisible by 16 already - if len(plain_text) % 16 != 0: - padding_count = 16 - len(plain_text) % 16 - plain_text += os.urandom(padding_count) + @staticmethod + def encrypt_ige(plain_text, key, iv): + """ + Encrypts the given text in 16-bytes blocks by using the + given key and 32-bytes initialization vector. + """ + # Add random padding iff it's not evenly divisible by 16 already + if len(plain_text) % 16 != 0: + padding_count = 16 - len(plain_text) % 16 + plain_text += os.urandom(padding_count) - iv1 = iv[:len(iv) // 2] - iv2 = iv[len(iv) // 2:] + if cryptg: + return cryptg.encrypt_ige(plain_text, key, iv) - aes = pyaes.AES(key) + iv1 = iv[:len(iv) // 2] + iv2 = iv[len(iv) // 2:] - cipher_text = [] - blocks_count = len(plain_text) // 16 + aes = pyaes.AES(key) - for block_index in range(blocks_count): - plain_text_block = list( - plain_text[block_index * 16:block_index * 16 + 16] - ) - for i in range(16): - plain_text_block[i] ^= iv1[i] + cipher_text = [] + blocks_count = len(plain_text) // 16 - cipher_text_block = aes.encrypt(plain_text_block) + for block_index in range(blocks_count): + plain_text_block = list( + plain_text[block_index * 16:block_index * 16 + 16] + ) + for i in range(16): + plain_text_block[i] ^= iv1[i] - for i in range(16): - cipher_text_block[i] ^= iv2[i] + cipher_text_block = aes.encrypt(plain_text_block) - iv1 = cipher_text_block - iv2 = plain_text[block_index * 16:block_index * 16 + 16] + for i in range(16): + cipher_text_block[i] ^= iv2[i] - cipher_text.extend(cipher_text_block) + iv1 = cipher_text_block + iv2 = plain_text[block_index * 16:block_index * 16 + 16] - return bytes(cipher_text) + cipher_text.extend(cipher_text_block) + + return bytes(cipher_text) diff --git a/telethon/crypto/libssl.py b/telethon/crypto/libssl.py deleted file mode 100644 index b4735112..00000000 --- a/telethon/crypto/libssl.py +++ /dev/null @@ -1,107 +0,0 @@ -""" -This module holds an AES IGE class, if libssl is available on the system. -""" -import os -import ctypes -from ctypes.util import find_library - -lib = find_library('ssl') -if not lib: - AES = None -else: - """ - # define AES_ENCRYPT 1 - # define AES_DECRYPT 0 - # define AES_MAXNR 14 - struct aes_key_st { - # ifdef AES_LONG - unsigned long rd_key[4 * (AES_MAXNR + 1)]; - # else - unsigned int rd_key[4 * (AES_MAXNR + 1)]; - # endif - int rounds; - }; - typedef struct aes_key_st AES_KEY; - - int AES_set_encrypt_key(const unsigned char *userKey, const int bits, - AES_KEY *key); - int AES_set_decrypt_key(const unsigned char *userKey, const int bits, - AES_KEY *key); - void AES_ige_encrypt(const unsigned char *in, unsigned char *out, - size_t length, const AES_KEY *key, - unsigned char *ivec, const int enc); - """ - _libssl = ctypes.cdll.LoadLibrary(lib) - - AES_MAXNR = 14 - AES_ENCRYPT = ctypes.c_int(1) - AES_DECRYPT = ctypes.c_int(0) - - 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), - ] - - class AES: - """ - Class that servers as an interface to encrypt and decrypt - text through the AES IGE mode, using the system's libssl. - """ - @staticmethod - def decrypt_ige(cipher_text, key, iv): - """ - Decrypts the given text in 16-bytes blocks by using the - given key and 32-bytes initialization vector. - """ - aeskey = AES_KEY() - ckey = (ctypes.c_ubyte * len(key))(*key) - cklen = ctypes.c_int(len(key)*8) - cin = (ctypes.c_ubyte * len(cipher_text))(*cipher_text) - ctlen = ctypes.c_size_t(len(cipher_text)) - cout = (ctypes.c_ubyte * len(cipher_text))() - civ = (ctypes.c_ubyte * len(iv))(*iv) - - _libssl.AES_set_decrypt_key(ckey, cklen, ctypes.byref(aeskey)) - _libssl.AES_ige_encrypt( - ctypes.byref(cin), - ctypes.byref(cout), - ctlen, - ctypes.byref(aeskey), - ctypes.byref(civ), - AES_DECRYPT - ) - - return bytes(cout) - - @staticmethod - def encrypt_ige(plain_text, key, iv): - """ - Encrypts the given text in 16-bytes blocks by using the - given key and 32-bytes initialization vector. - """ - # Add random padding iff it's not evenly divisible by 16 already - if len(plain_text) % 16 != 0: - padding_count = 16 - len(plain_text) % 16 - plain_text += os.urandom(padding_count) - - aeskey = AES_KEY() - ckey = (ctypes.c_ubyte * len(key))(*key) - cklen = ctypes.c_int(len(key)*8) - cin = (ctypes.c_ubyte * len(plain_text))(*plain_text) - ctlen = ctypes.c_size_t(len(plain_text)) - cout = (ctypes.c_ubyte * len(plain_text))() - civ = (ctypes.c_ubyte * len(iv))(*iv) - - _libssl.AES_set_encrypt_key(ckey, cklen, ctypes.byref(aeskey)) - _libssl.AES_ige_encrypt( - ctypes.byref(cin), - ctypes.byref(cout), - ctlen, - ctypes.byref(aeskey), - ctypes.byref(civ), - AES_ENCRYPT - ) - - return bytes(cout)