def encryptRsaWiener(msg: str): from Crypto.Util.number import getPrime, inverse from cryptostuff import encrypt bits = 2048 dBits = 200 bitsDifferencePQ = 50 i = 0 while True: p = getPrime(bits // 2 + bitsDifferencePQ) q = getPrime(bits // 2 - bitsDifferencePQ) d = getPrime(dBits) # print d e = inverse(d, (p - 1) * (q - 1)) if len(str(hex(e)[2:])) * 4 < bits - 5: # Very hacky and not very accurate but it serves its purpose: We want to ensure that e is not relatively small in relation to n. # print "e too small." i += 1 if i > 100: raise Exception( "Something is wrong in GameServerCrypto.encryptRsaWiener()" ) continue params = {"e": e, "n": p * q, "method": "saar"} msg += GameServerCrypto.parameterHash(params) return encrypt("saar", msg.encode("utf-8"), params), params, msg
def schwenkNew(msg: str, skipKeyAndIV=False): # import Crypto.Random import random import string from cryptostuff import encrypt if skipKeyAndIV: k = "" IV = "" else: k = "".join([ random.choice(string.printable) for _ in range(Schwenk.BLOCK_SIZE) ]) IV = "".join([ random.choice(string.printable) for _ in range(Schwenk.BLOCK_SIZE) ]) fakeHash = "".join( random.choice("0123456789abcdef") for _ in range(SHA512_HEX_LEN) ) # To be consistent with the other plaintext formats msg = k + IV + msg + fakeHash cipher, rawParams = Schwenk.encrypt(msg.encode("utf-8")) params = { "schwenkerid": rawParams[0], "schwenkingoptions": rawParams[1], "method": "schwenk" } cipher1 = encrypt("schwenk", msg.encode("utf-8"), params) assert cipher1 == cipher return cipher, params, msg
def encryptCaesar(msg: str): import random from cryptostuff import encrypt key = random.randint(-2**31, 2**31) params = {"key": key, "method": "caesar"} msg += GameServerCrypto.parameterHash(params) return encrypt("caesar", msg.encode("utf-8"), params), params, msg
def encryptOTP(msg: str): from cryptostuff import encrypt numBytes = len(msg) + 512 // 4 with open("/dev/urandom", "rb") as f: randBytes = f.read(numBytes) params = {"encryptionkey": hexlify(randBytes).decode("utf-8"), "method": "otp"} msg += GameServerCrypto.parameterHash(params) return encrypt("otp", msg.encode("utf-8"), params), params, msg
def checkEncryption(msg: str, cipher: bytes, params: dict): from cryptostuff import encrypt if params["method"] == "elgamal": # As the encryption is randomized, we cannot simply encrypt the known plaintext and compare the ciphertexts... # TODO: I don't think we can properly check this. With the known plaintext only. Otherwise, ElGamal would be pretty broken. pass else: cTest = encrypt(params["method"], msg.encode("utf-8"), params) if cTest != cipher: raise FlagMissingException(f"Incorrect cipher. Got {repr(cipher)}, expected {repr(cTest)}") return
def processCommand(self, message: str, signature: bytes): print("received message:", message, file=sys.stderr) msg = json.loads(message) if "command" not in msg: return ERROR_INVALID_COMMAND command = msg["command"] try: if command == "db_retrieve_item": time.sleep(5) dbId = msg["data"] item = self.loadItem(dbId) if item is None: return ERROR_INVALID_ITEM return '{"status":"db_retrieve_success", "data":"' + hexlify( item[0]).decode("utf-8") + '","params":' + json.dumps( item[1]) + '}' elif command == "db_store_item": if not self.isMessageFromTrustedClient(message, signature): return ERROR_INVALID_CLIENT id = msg["id"] params = msg["params"] cipher = unhexlify(msg["cipher"]) try: self.storeItem(id, cipher, params) except IntegrityError: return ERROR_ITEM_EXISTS return '{"status":"db_store_success"}' elif command == "check_item": if not self.isMessageFromTrustedClient(message, signature): return ERROR_INVALID_CLIENT dbId = msg["id"] item = self.loadItem((dbId)) if item is None: return ERROR_INVALID_ITEM c, params = item p = msg["msg"].encode("utf-8") try: c1 = cryptostuff.encrypt(params["method"], p, params) if c != c1: return '{"status":"check_fail"}' return '{"status":"check_success"}' except: return '{"status":"check_fail"}' else: return ERROR_INVALID_COMMAND except Exception as e: return ERROR_INTERNAL_SERVER_ERROR % (type(e), e)
def encryptRsaSmallFactor(msg: str): # We have a non-negligible probability for the message not being coprime to n. Hence, we need to check for this case. from Crypto.Util.number import getPrime, GCD, bytes_to_long from cryptostuff import encrypt bits = 2048 smallFactorBits = 10 e = 65537 i = 0 while True: bigFactorBits = bits - smallFactorBits p = getPrime(smallFactorBits) q = getPrime(bigFactorBits) n = p * q params = {"e": e, "n": n, "method": "saar"} m = msg + GameServerCrypto.parameterHash(params) if GCD(bytes_to_long(m.encode("utf-8")), n) == 1: return encrypt("saar", m.encode("utf-8"), params), params, m i += 1 if i > 50: raise Exception("Something is wrong in GameServerCrypto.encryptRsaSmallFactor()")
def checkEncryption(msg: str, cipher: bytes, params: dict): from cryptostuff import encrypt from cryptostuff import methods as encryptMethods if "method" not in params: raise MumbleException('Missing key: "method"') if params["method"] not in encryptMethods: raise MumbleException(f'Unknown method: "{params["method"]}"') if params["method"] == "elgamal": # As the encryption is randomized, we cannot simply encrypt the known plaintext and compare the ciphertexts... # TODO: I don't think we can properly check this. With the known plaintext only. Otherwise, ElGamal would be pretty broken. pass else: try: cTest = encrypt(params["method"], msg.encode("utf-8"), params) except Exception as e: raise MumbleException( f"Got exception {e} of type {type(e)} during encryption.") if cTest != cipher: raise FlagMissingException( f"Incorrect cipher. Got {repr(cipher)}, expected {repr(cTest)}. Params: " + str(params)) return
def encryptPlain(msg: str): from cryptostuff import encrypt params = {"method": "plain"} msg += GameServerCrypto.parameterHash(params) return encrypt("plain", msg.encode("utf-8"), params), params, msg