def _process_challenge(self, packet): authlog("processing challenge: %s", packet[1:]) def warn_server_and_exit(code, message, server_message="authentication failed"): authlog.error("Error: authentication failed:") authlog.error(" %s", message) self.disconnect_and_quit(code, server_message) if not self.password_file and not os.environ.get('XPRA_PASSWORD'): warn_server_and_exit(EXIT_PASSWORD_REQUIRED, "this server requires authentication, please provide a password", "no password available") return password = self.load_password() if not password: warn_server_and_exit(EXIT_PASSWORD_FILE_ERROR, "failed to load password from file %s" % self.password_file, "no password available") return salt = packet[1] if self.encryption: assert len(packet)>=3, "challenge does not contain encryption details to use for the response" server_cipher = typedict(packet[2]) key = self.get_encryption_key() if key is None: warn_server_and_exit(EXIT_ENCRYPTION, "the server does not use any encryption", "client requires encryption") return if not self.set_server_encryption(server_cipher, key): return #all server versions support a client salt, #they also tell us which digest to use: digest = packet[3] client_salt = get_hex_uuid()+get_hex_uuid() #TODO: use some key stretching algorigthm? (meh) try: from xpra.codecs.xor.cyxor import xor_str #@UnresolvedImport salt = xor_str(salt, client_salt) except: salt = xor(salt, client_salt) if digest==b"hmac": import hmac, hashlib def s(v): try: return v.encode() except: return str(v) password = s(password) salt = s(salt) challenge_response = hmac.HMAC(password, salt, digestmod=hashlib.md5).hexdigest() elif digest==b"xor": #don't send XORed password unencrypted: if not self._protocol.cipher_out and not ALLOW_UNENCRYPTED_PASSWORDS: warn_server_and_exit(EXIT_ENCRYPTION, "server requested digest %s, cowardly refusing to use it without encryption" % digest, "invalid digest") return challenge_response = xor(password, salt) else: warn_server_and_exit(EXIT_PASSWORD_REQUIRED, "server requested an unsupported digest: %s" % digest, "invalid digest") return if digest: authlog("%s(%s, %s)=%s", digest, binascii.hexlify(password), binascii.hexlify(salt), challenge_response) self.password_sent = True self.remove_packet_handlers("challenge") self.send_hello(challenge_response, client_salt)
def _process_challenge(self, packet): log("processing challenge: %s", packet[1:]) if not self.password_file: self.warn_and_quit( EXIT_PASSWORD_REQUIRED, "server requires authentication, please provide a password") return password = self.load_password() if not password: self.warn_and_quit( EXIT_PASSWORD_FILE_ERROR, "failed to load password from file %s" % self.password_file) return salt = packet[1] if self.encryption: assert len( packet ) >= 3, "challenge does not contain encryption details to use for the response" server_cipher = packet[2] key = self.get_encryption_key() if key is None: self.warn_and_quit(EXIT_ENCRYPTION, "encryption key is missing") return if not self.set_server_encryption(server_cipher, key): return digest = "hmac" client_can_salt = len(packet) >= 4 client_salt = None if client_can_salt: #server supports client salt, and tells us which digest to use: digest = packet[3] client_salt = get_hex_uuid() + get_hex_uuid() #TODO: use some key stretching algorigthm? (meh) salt = xor(salt, client_salt) if digest == "hmac": import hmac challenge_response = hmac.HMAC(password, salt).hexdigest() elif digest == "xor": #don't send XORed password unencrypted: if not self._protocol.cipher_out and not ALLOW_UNENCRYPTED_PASSWORDS: self.warn_and_quit( EXIT_ENCRYPTION, "server requested digest %s, cowardly refusing to use it without encryption" % digest) return challenge_response = xor(password, salt) else: self.warn_and_quit( EXIT_PASSWORD_REQUIRED, "server requested an unsupported digest: %s" % digest) return if digest: log("%s(%s, %s)=%s", digest, password, salt, challenge_response) self.password_sent = True self.send_hello(challenge_response, client_salt)
def _process_challenge(self, packet): log("processing challenge: %s", packet[1:]) if not self.password_file and not os.environ.get('XPRA_PASSWORD'): self.warn_and_quit(EXIT_PASSWORD_REQUIRED, "server requires authentication, please provide a password") return password = self.load_password() if not password: self.warn_and_quit(EXIT_PASSWORD_FILE_ERROR, "failed to load password from file %s" % self.password_file) return salt = packet[1] if self.encryption: assert len(packet)>=3, "challenge does not contain encryption details to use for the response" server_cipher = packet[2] key = self.get_encryption_key() if key is None: self.warn_and_quit(EXIT_ENCRYPTION, "encryption key is missing") return if not self.set_server_encryption(server_cipher, key): return digest = "hmac" client_can_salt = len(packet)>=4 client_salt = None if client_can_salt: #server supports client salt, and tells us which digest to use: digest = packet[3] client_salt = get_hex_uuid()+get_hex_uuid() #TODO: use some key stretching algorigthm? (meh) salt = xor(salt, client_salt) if digest=="hmac": import hmac challenge_response = hmac.HMAC(password, salt).hexdigest() elif digest=="xor": #don't send XORed password unencrypted: if not self._protocol.cipher_out and not ALLOW_UNENCRYPTED_PASSWORDS: self.warn_and_quit(EXIT_ENCRYPTION, "server requested digest %s, cowardly refusing to use it without encryption" % digest) return challenge_response = xor(password, salt) else: self.warn_and_quit(EXIT_PASSWORD_REQUIRED, "server requested an unsupported digest: %s" % digest) return if digest: log("%s(%s, %s)=%s", digest, password, salt, challenge_response) self.password_sent = True for d in (self._packet_handlers, self._ui_packet_handlers): try: del d["challenge"] except: pass self.send_hello(challenge_response, client_salt)
def authenticate(self, challenge_response, client_salt): global password_file if not self.salt: log.error("illegal challenge response received - salt cleared or unset") return None #ensure this salt does not get re-used: if client_salt is None: salt = self.salt else: salt = xor(self.salt, client_salt) self.salt = None entry = self.get_entry() if entry is None: log.error("usename %s does not exist in %s", self.username, password_file) return None fpassword, uid, gid, displays, env_options, session_options = entry verify = hmac.HMAC(fpassword, salt).hexdigest() log("authenticate(%s) password=%s, hex(salt)=%s, hash=%s", challenge_response, fpassword, binascii.hexlify(salt), verify) if hasattr(hmac, "compare_digest"): eq = hmac.compare_digest(verify, challenge_response) else: eq = verify==challenge_response if not eq: log("expected '%s' but got '%s'", verify, challenge_response) log.error("hmac password challenge for %s does not match", self.username) return False self.sessions = uid, gid, displays, env_options, session_options return True
def authenticate_hmac(self, challenge_response, client_salt): if not self.salt: log.error("Error: illegal challenge response received - salt cleared or unset") return None #ensure this salt does not get re-used: if client_salt is None: salt = self.salt else: salt = xor(self.salt, client_salt) self.salt = None password = self.get_password() if not password: log.error("Error: %s authentication failed", self) log.error(" no password defined for '%s'", self.username) return False verify = hmac.HMAC(strtobytes(password), strtobytes(salt), digestmod=hashlib.md5).hexdigest() log("authenticate(%s) password=%s, hex(salt)=%s, hash=%s", challenge_response, password, binascii.hexlify(strtobytes(salt)), verify) if hasattr(hmac, "compare_digest"): eq = hmac.compare_digest(verify, challenge_response) else: eq = verify==challenge_response if not eq: log("expected '%s' but got '%s'", verify, challenge_response) log.error("Error: hmac password challenge for '%s' does not match", self.username) return False return True
def _test_file_auth(self, name, module, genauthdata): #no file, no go: a = self._init_auth(module) assert a.requires_challenge() p = a.get_password() assert not p, "got a password from %s: %s" % (a, p) #challenge twice is a fail assert a.get_challenge() assert not a.get_challenge() assert not a.get_challenge() for muck in (0, 1): f = tempfile.NamedTemporaryFile(prefix=name) filename = f.name with f: a = self._init_auth(module, {"password_file" : filename}) password, filedata = genauthdata(a) print("saving password file data='%s' to '%s'", filedata, filename) f.write(strtobytes(filedata)) f.flush() assert a.requires_challenge() salt, mac = a.get_challenge() assert salt assert mac=="hmac" password = strtobytes(password) client_salt = strtobytes(uuid.uuid4().hex+uuid.uuid4().hex) auth_salt = strtobytes(xor(salt, client_salt)) if muck==0: verify = hmac.HMAC(password, auth_salt, digestmod=hashlib.md5).hexdigest() assert a.authenticate(verify, client_salt) assert not a.authenticate(verify, client_salt) assert a.get_password()==password elif muck==1: for verify in ("whatever", None, "bad"): assert not a.authenticate(verify, client_salt)
def authenticate_hmac(self, challenge_response, client_salt): if not self.salt: log.error( "Error: illegal challenge response received - salt cleared or unset" ) return None #ensure this salt does not get re-used: if client_salt is None: salt = self.salt else: salt = xor(self.salt, client_salt) self.salt = None password = self.get_password() if not password: log.error("Error: %s authentication failed", self) log.error(" no password defined for '%s'", self.username) return False verify = hmac.HMAC(strtobytes(password), strtobytes(salt), digestmod=hashlib.md5).hexdigest() log("authenticate(%s) password=%s, hex(salt)=%s, hash=%s", challenge_response, password, binascii.hexlify(strtobytes(salt)), verify) if hasattr(hmac, "compare_digest"): eq = hmac.compare_digest(verify, challenge_response) else: eq = verify == challenge_response if not eq: log("expected '%s' but got '%s'", verify, challenge_response) log.error("Error: hmac password challenge for '%s' does not match", self.username) return False return True
def authenticate(self, challenge_response, client_salt): global password_file if not self.salt: log.error( "illegal challenge response received - salt cleared or unset") return None #ensure this salt does not get re-used: if client_salt is None: salt = self.salt else: salt = xor(self.salt, client_salt) self.salt = None entry = self.get_entry() if entry is None: log.error("usename %s does not exist in %s", self.username, password_file) return None fpassword, uid, gid, displays, env_options, session_options = entry verify = hmac.HMAC(fpassword, salt).hexdigest() log("authenticate(%s) password=%s, hex(salt)=%s, hash=%s", challenge_response, fpassword, binascii.hexlify(salt), verify) if hasattr(hmac, "compare_digest"): eq = hmac.compare_digest(verify, challenge_response) else: eq = verify == challenge_response if not eq: log("expected '%s' but got '%s'", verify, challenge_response) log.error("hmac password challenge for %s does not match", self.username) return False self.sessions = uid, gid, displays, env_options, session_options return True
def authenticate_hmac(self, challenge_response, client_salt): self.sessions = None if not self.salt: log.error("Error: illegal challenge response received - salt cleared or unset") return None #ensure this salt does not get re-used: if client_salt is None: salt = self.salt else: salt = xor(self.salt, client_salt) self.salt = None entry = self.get_auth_info() log("authenticate(%s) auth-info=%s", self.username, entry) if entry is None: log.error("Error: authentication failed") log.error(" no password for '%s' in '%s'", self.username, self.password_filename) return None fpassword, uid, gid, displays, env_options, session_options = entry verify = hmac.HMAC(strtobytes(fpassword), strtobytes(salt), digestmod=hashlib.md5).hexdigest() log("authenticate(%s) password='******', hex(salt)=%s, hash=%s", challenge_response, fpassword, binascii.hexlify(strtobytes(salt)), verify) if not hmac.compare_digest(verify, challenge_response): log("expected '%s' but got '%s'", verify, challenge_response) log.error("Error: hmac password challenge for '%s' does not match", self.username) return False self.sessions = uid, gid, displays, env_options, session_options return True
def main(argv): from xpra.util import xor from xpra.net.digest import get_salt, get_digests, gendigest from xpra.platform import program_context with program_context("LDAP-Password-Auth", "LDAP-Password-Authentication"): for x in list(argv): if x in ("-v", "--verbose"): enable_debug_for("auth") argv.remove(x) if len(argv) not in (3,4,5,6,7): sys.stderr.write("%s invalid arguments\n" % argv[0]) sys.stderr.write("usage: %s username password [host] [port] [tls] [username_format]\n" % argv[0]) return 1 username = argv[1] password = argv[2] kwargs = {} if len(argv)>=4: kwargs["host"] = argv[3] if len(argv)>=5: kwargs["port"] = argv[4] if len(argv)>=6: kwargs["tls"] = argv[5] if len(argv)>=7: kwargs["username_format"] = argv[6] a = Authenticator(username, **kwargs) server_salt, digest = a.get_challenge(["xor"]) salt_digest = a.choose_salt_digest(get_digests()) assert digest=="xor" client_salt = get_salt(len(server_salt)) combined_salt = gendigest(salt_digest, client_salt, server_salt) response = xor(password, combined_salt) r = a.authenticate(response, client_salt) print("success: %s" % r) return int(not r)
def _test_file_auth(self, name, module, genauthdata): #no file, no go: a = self._init_auth(module) assert a.requires_challenge() p = a.get_password() assert not p, "got a password from %s: %s" % (a, p) #challenge twice is a fail assert a.get_challenge() assert not a.get_challenge() assert not a.get_challenge() for muck in (0, 1): f = tempfile.NamedTemporaryFile(prefix=name) filename = f.name with f: a = self._init_auth(module, {"password_file" : filename}) password, filedata = genauthdata(a) #print("saving password file data='%s' to '%s'" % (filedata, filename)) f.write(strtobytes(filedata)) f.flush() assert a.requires_challenge() salt, mac = a.get_challenge() assert salt assert mac=="hmac" password = strtobytes(password) client_salt = strtobytes(uuid.uuid4().hex+uuid.uuid4().hex) auth_salt = strtobytes(xor(salt, client_salt)) if muck==0: verify = hmac.HMAC(password, auth_salt, digestmod=hashlib.md5).hexdigest() assert a.authenticate(verify, client_salt) assert not a.authenticate(verify, client_salt) assert a.get_password()==password elif muck==1: for verify in ("whatever", None, "bad"): assert not a.authenticate(verify, client_salt)
def main(argv): from xpra.platform import program_context with program_context("Kerberos-Password-Auth", "Kerberos-Password-Authentication"): if len(argv) not in (3, 4, 5): sys.stderr.write("%s invalid arguments\n" % argv[0]) sys.stderr.write( "usage: %s username password [service [realm]]\n" % argv[0]) return 1 username = argv[1] password = argv[2] kwargs = {} if len(argv) >= 4: kwargs["service"] = argv[3] if len(argv) == 5: kwargs["realm"] = argv[4] a = Authenticator(username, **kwargs) server_salt, digest = a.get_challenge(["xor"]) salt_digest = a.choose_salt_digest(get_digests()) assert digest == "xor" client_salt = get_salt(len(server_salt)) combined_salt = gendigest(salt_digest, client_salt, server_salt) response = xor(password, combined_salt) a.authenticate(response, client_salt) return 0
def authenticate(self, challenge_response, client_salt): global socket_dir if self.salt is None: log.error("got a challenge response with no salt!") return False if client_salt is None: salt = self.salt else: salt = xor(self.salt, client_salt) self.salt = None password = xor(challenge_response, salt) #warning: enabling logging here would log the actual system password! #log("authenticate(%s) password=%s", challenge_response, password) #verify login: try : if not self.check(password): return False except Exception, e: log.error("authentication error: %s", e) return False
def authenticate_check(self, challenge_response, client_salt): if self.salt is None: log.error("Error: illegal challenge response received - salt cleared or unset") return False if client_salt is None: salt = self.salt else: salt = xor(self.salt, client_salt) self.salt = None password = xor(challenge_response, salt) #warning: enabling logging here would log the actual system password! #log("authenticate(%s) password=%s", challenge_response, password) #verify login: try : ret = self.check(password) log("check(..)=%s", ret) except Exception as e: log.error("Error in %s authentication checks:", self) log.error(" %s", e) return False return ret
def authenticate_check(self, challenge_response, client_salt): if self.salt is None: log.error( "Error: illegal challenge response received - salt cleared or unset" ) return False if client_salt is None: salt = self.salt else: salt = xor(self.salt, client_salt) self.salt = None password = xor(challenge_response, salt) #warning: enabling logging here would log the actual system password! #log("authenticate(%s) password=%s", challenge_response, password) #verify login: try: ret = self.check(password) log("authenticate_check(..)=%s", ret) except Exception as e: log.error("Error: %s authentication check failed:", self) log.error(" %s", e) return False return ret
def _test_hmac_auth(self, auth_class, password, **kwargs): for x in (password, "somethingelse"): a = self._init_auth(auth_class, **kwargs) assert a.requires_challenge() assert a.get_password() salt, mac = a.get_challenge() assert salt assert mac=="hmac", "invalid mac: %s" % mac client_salt = strtobytes(uuid.uuid4().hex+uuid.uuid4().hex) auth_salt = strtobytes(xor(salt, client_salt)) verify = hmac.HMAC(x, auth_salt, digestmod=hashlib.md5).hexdigest() passed = a.authenticate(verify, client_salt) assert passed == (x==password), "expected authentication to %s with %s vs %s" % (["fail", "succeed"][x==password], x, password) assert not a.authenticate(verify, client_salt)
def gendigest(digest, password, salt): assert digest and password and salt salt = memoryview_to_bytes(salt) password = strtobytes(password) if digest == "xor": salt = salt.ljust(len(password), "\x00")[:len(password)] return memoryview_to_bytes(xor(password, salt)) digestmod = get_digest_module(digest) if not digestmod: log("invalid digest module '%s'", digest) return None #warn_server_and_exit(EXIT_UNSUPPORTED, "server requested digest '%s' but it is not supported" % digest, "invalid digest") v = hmac.HMAC(strtobytes(password), strtobytes(salt), digestmod=digestmod).hexdigest() return v
def main(argv): from xpra.platform import program_context with program_context("GSS-Auth", "GSS-Authentication"): if len(argv) != 3: sys.stderr.write("%s invalid arguments\n" % argv[0]) sys.stderr.write("usage: %s username token\n" % argv[0]) return 1 username = argv[1] token = argv[2] kwargs = {} a = Authenticator(username, **kwargs) server_salt, digest = a.get_challenge(["xor"]) salt_digest = a.choose_salt_digest(get_digests()) assert digest == "xor" client_salt = get_salt(len(server_salt)) combined_salt = gendigest(salt_digest, client_salt, server_salt) response = xor(token, combined_salt) a.authenticate(response, client_salt) return 0
def gendigest(digest, password, salt): assert digest and password and salt salt = memoryview_to_bytes(salt) password = strtobytes(password) if digest == "des": from xpra.net.d3des import generate_response password = password.ljust(8, "\x00")[:8] salt = salt.ljust(16, "\x00")[:16] v = generate_response(password, salt) return hexstr(v) elif digest == "xor": salt = salt.ljust(16, "\x00")[:len(password)] return memoryview_to_bytes(xor(password, salt)) digestmod = get_digest_module(digest) if not digestmod: log("invalid digest module '%s': %s", digest) return None #warn_server_and_exit(EXIT_UNSUPPORTED, "server requested digest '%s' but it is not supported" % digest, "invalid digest") v = hmac.HMAC(strtobytes(password), strtobytes(salt), digestmod=digestmod).hexdigest() return v
def authenticate_hmac(self, challenge_response, client_salt): self.sessions = None if not self.salt: log.error( "Error: illegal challenge response received - salt cleared or unset" ) return None #ensure this salt does not get re-used: if client_salt is None: salt = self.salt else: salt = xor(self.salt, client_salt) self.salt = None entry = self.get_auth_info() log("authenticate(%s) auth-info=%s", self.username, entry) if entry is None: log.error("Error: authentication failed") log.error(" no password for '%s' in '%s'", self.username, self.password_filename) return None fpassword, uid, gid, displays, env_options, session_options = entry verify = hmac.HMAC(strtobytes(fpassword), strtobytes(salt), digestmod=hashlib.md5).hexdigest() log("authenticate(%s) password='******', hex(salt)=%s, hash=%s", challenge_response, fpassword, binascii.hexlify(strtobytes(salt)), verify) if hasattr(hmac, "compare_digest"): eq = hmac.compare_digest(verify, challenge_response) else: eq = verify == challenge_response if not eq: log("expected '%s' but got '%s'", verify, challenge_response) log.error("Error: hmac password challenge for '%s' does not match", self.username) return False self.sessions = uid, gid, displays, env_options, session_options return True
def gendigest(digest, password, salt): assert digest and password and salt salt = memoryview_to_bytes(salt) password = strtobytes(password) if digest=="des": from xpra.net.d3des import generate_response password = password.ljust(8, b"\x00")[:8] salt = salt.ljust(16, b"\x00")[:16] v = generate_response(password, salt) return hexstr(v) elif digest in ("xor", "kerberos", "gss"): #kerberos and gss use xor because we need to use the actual token #at the other end salt = salt.ljust(len(password), b"\x00")[:len(password)] v = xor(password, salt) return memoryview_to_bytes(v) digestmod = get_digest_module(digest) if not digestmod: log("invalid digest module '%s': %s", digest) return None #warn_server_and_exit(EXIT_UNSUPPORTED, "server requested digest '%s' but it is not supported" % digest, "invalid digest") v = hmac.HMAC(strtobytes(password), strtobytes(salt), digestmod=digestmod).hexdigest() return v
def _process_challenge(self, packet): authlog("processing challenge: %s", packet[1:]) def warn_server_and_exit(code, message, server_message="authentication failed"): authlog.error("Error: authentication failed:") authlog.error(" %s", message) self.disconnect_and_quit(code, server_message) if not self.has_password(): warn_server_and_exit( EXIT_PASSWORD_REQUIRED, "this server requires authentication, please provide a password", "no password available") return password = self.load_password() if not password: warn_server_and_exit( EXIT_PASSWORD_FILE_ERROR, "failed to load password from file %s" % self.password_file, "no password available") return server_salt = packet[1] if self.encryption: assert len( packet ) >= 3, "challenge does not contain encryption details to use for the response" server_cipher = typedict(packet[2]) key = self.get_encryption_key() if key is None: warn_server_and_exit(EXIT_ENCRYPTION, "the server does not use any encryption", "client requires encryption") return if not self.set_server_encryption(server_cipher, key): return #all server versions support a client salt, #they also tell us which digest to use: digest = bytestostr(packet[3]) l = len(server_salt) salt_digest = "xor" if len(packet) >= 5: salt_digest = bytestostr(packet[4]) if salt_digest == "xor": #with xor, we have to match the size assert l >= 16, "server salt is too short: only %i bytes, minimum is 16" % l assert l <= 256, "server salt is too long: %i bytes, maximum is 256" % l else: #other digest, 32 random bytes is enough: l = 32 client_salt = get_salt(l) if salt_digest in ("xor", "des"): if not LEGACY_SALT_DIGEST: warn_server_and_exit( EXIT_INCOMPATIBLE_VERSION, "server uses legacy salt digest '%s'" % salt_digest, "unsupported digest %s" % salt_digest) return log.warn( "Warning: server using legacy support for '%s' salt digest", salt_digest) salt = gendigest(salt_digest, client_salt, server_salt) authlog("combined %s salt(%s, %s)=%s", salt_digest, binascii.hexlify(server_salt), binascii.hexlify(client_salt), binascii.hexlify(salt)) if digest.startswith(b"hmac"): import hmac digestmod = get_digest_module(digest) if not digestmod: log("invalid digest module '%s': %s", digest) warn_server_and_exit( EXIT_UNSUPPORTED, "server requested digest '%s' but it is not supported" % digest, "invalid digest") return password = strtobytes(password) salt = memoryview_to_bytes(salt) challenge_response = hmac.HMAC(password, salt, digestmod=digestmod).hexdigest() authlog("hmac.HMAC(%s, %s)=%s", binascii.hexlify(password), binascii.hexlify(salt), challenge_response) elif digest == b"xor": #don't send XORed password unencrypted: encrypted = self._protocol.cipher_out or self._protocol.get_info( ).get("type") == "ssl" local = self.display_desc.get("local", False) authlog("xor challenge, encrypted=%s, local=%s", encrypted, local) if local and ALLOW_LOCALHOST_PASSWORDS: pass elif not encrypted and not ALLOW_UNENCRYPTED_PASSWORDS: warn_server_and_exit( EXIT_ENCRYPTION, "server requested digest %s, cowardly refusing to use it without encryption" % digest, "invalid digest") return salt = salt[:len(password)] challenge_response = memoryview_to_bytes(xor(password, salt)) else: warn_server_and_exit( EXIT_PASSWORD_REQUIRED, "server requested an unsupported digest: %s" % digest, "invalid digest") return if digest: authlog("%s(%s, %s)=%s", digest, binascii.hexlify(password), binascii.hexlify(salt), binascii.hexlify(challenge_response)) self.password_sent = True self.remove_packet_handlers("challenge") self.send_hello(challenge_response, client_salt)
def test_xor(self): self.assertEqual(xor("A", "a"), xor("B", "b"))
def _process_challenge(self, packet): authlog("processing challenge: %s", packet[1:]) def warn_server_and_exit(code, message, server_message="authentication failed"): authlog.error("Error: authentication failed:") authlog.error(" %s", message) self.disconnect_and_quit(code, server_message) if not self.has_password(): warn_server_and_exit( EXIT_PASSWORD_REQUIRED, "this server requires authentication, please provide a password", "no password available") return password = self.load_password() if not password: warn_server_and_exit( EXIT_PASSWORD_FILE_ERROR, "failed to load password from file %s" % self.password_file, "no password available") return salt = packet[1] if self.encryption: assert len( packet ) >= 3, "challenge does not contain encryption details to use for the response" server_cipher = typedict(packet[2]) key = self.get_encryption_key() if key is None: warn_server_and_exit(EXIT_ENCRYPTION, "the server does not use any encryption", "client requires encryption") return if not self.set_server_encryption(server_cipher, key): return #all server versions support a client salt, #they also tell us which digest to use: digest = packet[3] client_salt = get_salt(len(salt)) #TODO: use some key stretching algorigthm? (meh) try: from xpra.codecs.xor.cyxor import xor_str #@UnresolvedImport salt = xor_str(salt, client_salt) except: salt = xor(salt, client_salt) if digest == b"hmac": import hmac, hashlib password = strtobytes(password) salt = strtobytes(salt) challenge_response = hmac.HMAC(password, salt, digestmod=hashlib.md5).hexdigest() elif digest == b"xor": #don't send XORed password unencrypted: if not self._protocol.cipher_out and not ALLOW_UNENCRYPTED_PASSWORDS: warn_server_and_exit( EXIT_ENCRYPTION, "server requested digest %s, cowardly refusing to use it without encryption" % digest, "invalid digest") return salt = salt[:len(password)] challenge_response = strtobytes(xor(password, salt)) else: warn_server_and_exit( EXIT_PASSWORD_REQUIRED, "server requested an unsupported digest: %s" % digest, "invalid digest") return if digest: authlog("%s(%s, %s)=%s", digest, binascii.hexlify(password), binascii.hexlify(salt), challenge_response) self.password_sent = True self.remove_packet_handlers("challenge") self.send_hello(challenge_response, client_salt)
def _process_challenge(self, packet): authlog("processing challenge: %s", packet[1:]) def warn_server_and_exit(code, message, server_message="authentication failed"): authlog.error("Error: authentication failed:") authlog.error(" %s", message) self.disconnect_and_quit(code, server_message) if not self.has_password(): warn_server_and_exit( EXIT_PASSWORD_REQUIRED, "this server requires authentication, please provide a password", "no password available", ) return password = self.load_password() if not password: warn_server_and_exit( EXIT_PASSWORD_FILE_ERROR, "failed to load password from file %s" % self.password_file, "no password available", ) return salt = packet[1] if self.encryption: assert len(packet) >= 3, "challenge does not contain encryption details to use for the response" server_cipher = typedict(packet[2]) key = self.get_encryption_key() if key is None: warn_server_and_exit( EXIT_ENCRYPTION, "the server does not use any encryption", "client requires encryption" ) return if not self.set_server_encryption(server_cipher, key): return # all server versions support a client salt, # they also tell us which digest to use: digest = packet[3] client_salt = get_salt(len(salt)) # TODO: use some key stretching algorigthm? (meh) salt = xor(salt, client_salt) if digest == b"hmac": import hmac, hashlib password = strtobytes(password) salt = strtobytes(salt) challenge_response = hmac.HMAC(password, salt, digestmod=hashlib.md5).hexdigest() elif digest == b"xor": # don't send XORed password unencrypted: encrypted = self._protocol.cipher_out or self._protocol.get_info().get("type") == "ssl" local = self.display_desc.get("local", False) authlog("xor challenge, encrypted=%s, local=%s", encrypted, local) if local and ALLOW_LOCALHOST_PASSWORDS: pass elif not encrypted and not ALLOW_UNENCRYPTED_PASSWORDS: warn_server_and_exit( EXIT_ENCRYPTION, "server requested digest %s, cowardly refusing to use it without encryption" % digest, "invalid digest", ) return salt = salt[: len(password)] challenge_response = strtobytes(xor(password, salt)) else: warn_server_and_exit( EXIT_PASSWORD_REQUIRED, "server requested an unsupported digest: %s" % digest, "invalid digest" ) return if digest: authlog("%s(%s, %s)=%s", digest, binascii.hexlify(password), binascii.hexlify(salt), challenge_response) self.password_sent = True self.remove_packet_handlers("challenge") self.send_hello(challenge_response, client_salt)