You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

238 lines
7.5 KiB

# -*- 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
import ssl
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://api.cryptolens.io/api/"
verify_SSL = True
proxy_experimental = False
@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, hlen = 256):
import hashlib
h = hashlib.sha256()
if hlen == 512:
h = hashlib.sha512()
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
if hlen == 512:
T = bytes([0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05, 0x00, 0x04, 0x40]) + 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, l=256):
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, l)
if EM2 is None: return False
try:
import hmac
return hmac.compare_digest(EM, EM2)
except (ImportError, AttributeError):
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 verify_signature_metadata(signature, rsaPublicKey):
import base64
import json
n = HelperMethods.OS2IP(base64.b64decode(rsaPublicKey.modulus))
e = HelperMethods.OS2IP(base64.b64decode(rsaPublicKey.exponent))
data = json.loads(base64.b64decode(signature))
d = base64.b64decode(data["Data"])
s = base64.b64decode(data["Signature"])
return [HelperMethods.RSAASSA_PKCS1_V15_VERIFY((n,e), d,s, l=512), d]
@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
"""
if HelperMethods.verify_SSL:
req = urllib.request.Request(HelperMethods.server_address + method, \
urllib.parse.urlencode(params)\
.encode("utf-8"))
if HelperMethods.proxy_experimental == True:
proxies = urllib.request.getproxies()
if HelperMethods.proxy_experimental:
from urllib.parse import urlparse
for scheme, proxy_uri in urllib.request.getproxies().items():
req.set_proxy(urlparse(proxy_uri).netloc, scheme)
return urllib.request.urlopen(req).read().decode("utf-8")
else:
return urllib.request.urlopen(req).read().decode("utf-8")
else:
ctx = ssl.create_default_context()
ctx.check_hostname = False
ctx.verify_mode = ssl.CERT_NONE
return urllib.request.urlopen(HelperMethods.server_address + method, \
urllib.parse.urlencode(params)\
.encode("utf-8"), context=ctx).read().decode("utf-8")
@staticmethod
def start_process_ps_v2():
ps_args = "-Command (Get-CimInstance -Class Win32_ComputerSystemProduct).UUID"
cmd = ["powershell", *ps_args.split(" ")]
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
out, err = proc.communicate(timeout=120)
rawOutput = out.decode('utf-8').strip()
return rawOutput
@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()