# -*- coding: utf-8 -*- """ Created on Wed Jan 23 10:12:13 2019 @author: Artem Los """ import base64 import urllib.request import hashlib import subprocess import os, os.path def subprocess_args(include_stdout=True): if hasattr(subprocess, 'STARTUPINFO'): si = subprocess.STARTUPINFO() si.dwFlags |= subprocess.STARTF_USESHOWWINDOW env = os.environ else: si = None env = None if include_stdout: ret = {'stdout': subprocess.PIPE} else: ret = {} ret.update({'stdin': subprocess.PIPE, 'stderr': subprocess.PIPE, 'startupinfo': si, 'env': env }) return ret class HelperMethods: server_address = "https://app.cryptolens.io/api/" @staticmethod def get_SHA256(string): """ Compute the SHA256 signature of a string. """ return hashlib.sha256(string.encode("utf-8")).hexdigest() @staticmethod def I2OSP(x, xLen): if x > (1 << (8 * xLen)): return None Xrev = [] for _ in range(0, xLen): x, m = divmod(x, 256) Xrev.append(m) return bytes(reversed(Xrev)) @staticmethod def OS2IP(X): import binascii h = binascii.hexlify(X) return int(h, 16) @staticmethod def RSAVP1(pair, s): n, e = pair if s < 0 or n-1 < s: return None return pow(s, e, n) @staticmethod def EMSA_PKCS1_V15_ENCODE(M, emLen): import hashlib h = hashlib.sha256() h.update(M) H = h.digest() T = bytes([0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20]) + H tLen = len(T) if emLen < tLen + 11: return None PS = bytes([0xff for _ in range(emLen - tLen - 3)]) return b"".join([b"\x00\x01", PS, b"\x00", T]) @staticmethod def RSAASSA_PKCS1_V15_VERIFY(pair, M, S): n, e = pair s = HelperMethods.OS2IP(S) m = HelperMethods.RSAVP1((n,e), s) if m is None: return False EM = HelperMethods.I2OSP(m, 256) if EM is None: return False EM2 = HelperMethods.EMSA_PKCS1_V15_ENCODE(M, 256) # Can return None, but it's OK since EM is not None return EM == EM2 @staticmethod def verify_signature(response, rsaPublicKey): """ Verifies a signature from .NET RSACryptoServiceProvider. """ n = HelperMethods.OS2IP(base64.b64decode(rsaPublicKey.modulus)) e = HelperMethods.OS2IP(base64.b64decode(rsaPublicKey.exponent)) m = base64.b64decode(response.license_key) r = base64.b64decode(response.signature) return HelperMethods.RSAASSA_PKCS1_V15_VERIFY((n,e), m, r) @staticmethod def int2base64(num): return base64.b64encode(int.to_bytes(num), byteorder='big') @staticmethod def base642int(string): return int.from_bytes(base64.b64decode((string)), byteorder='big') @staticmethod def send_request(method, params): """ Send a POST request to method in the Web API with the specified params and return the response string. method: the path of the method, eg. key/activate params: a dictionary of parameters """ return urllib.request.urlopen(HelperMethods.server_address + method, \ urllib.parse.urlencode(params)\ .encode("utf-8")).read().decode("utf-8") @staticmethod def start_process(command, v = 1): output = subprocess.check_output(command, **subprocess_args(False)) if v == 1: return output.decode('utf-8') elif v == 2: rawOutput = output.decode('utf-8') return rawOutput[rawOutput.index("UUID")+4:].strip() else: raise ValueError("Version can be either 1 or 2.") @staticmethod def get_dbus_machine_id(): try: with open("/etc/machine-id") as f: return f.read().strip() except: pass try: with open("/var/lib/dbus/machine-id") as f: return f.read().strip() except: pass return "" @staticmethod def get_inodes(): import os files = ["/bin", "/etc", "/lib", "/root", "/sbin", "/usr", "/var"] inodes = [] for file in files: try: inodes.append(os.stat(file).st_ino) except: pass return "".join([str(x) for x in inodes]) @staticmethod def compute_machine_code(): return HelperMethods.get_dbus_machine_id() + HelperMethods.get_inodes()