Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1# This file is part of Xpra. 

2# Copyright (C) 2011-2018 Antoine Martin <antoine@xpra.org> 

3# Xpra is released under the terms of the GNU GPL v2, or, at your option, any 

4# later version. See the file COPYING for details. 

5 

6import os 

7import hmac 

8import hashlib 

9 

10from xpra.util import csv 

11from xpra.log import Logger 

12from xpra.os_util import strtobytes, memoryview_to_bytes, hexstr 

13 

14log = Logger("network", "crypto") 

15 

16BLACKLISTED_HASHES = ("sha1", "md5") 

17 

18 

19def get_digests(): 

20 digests = ["xor"] 

21 digests += ["hmac+%s" % x for x in tuple(reversed(sorted(hashlib.algorithms_available))) 

22 if not x.startswith("shake_") and x not in BLACKLISTED_HASHES 

23 and getattr(hashlib, x, None) is not None] 

24 try: 

25 from xpra.net import d3des 

26 assert d3des 

27 digests.append("des") 

28 except (ImportError, TypeError): # pragma: no cover 

29 pass 

30 return digests 

31 

32def get_digest_module(digest : str): 

33 log("get_digest_module(%s)", digest) 

34 if not digest or not digest.startswith("hmac"): 

35 return None 

36 try: 

37 digest_module = digest.split("+")[1] #ie: "hmac+sha512" -> "sha512" 

38 except IndexError: 

39 return None 

40 try: 

41 return getattr(hashlib, digest_module) 

42 except AttributeError as e: 

43 log("no '%s' attribute in hashlib: %s", digest_module, e) 

44 return None 

45 

46def choose_digest(options) -> str: 

47 assert len(options)>0, "no digest options" 

48 log("choose_digest(%s)", options) 

49 #prefer stronger hashes: 

50 for h in ("sha512", "sha384", "sha256", "sha224"): 

51 hname = "hmac+%s" % h 

52 if hname in options: 

53 return hname 

54 if "xor" in options: 

55 return "xor" 

56 if "des" in options: 

57 return "des" 

58 raise ValueError("no known digest options found in '%s'" % csv(options)) 

59 

60def gendigest(digest, password, salt): 

61 assert password and salt 

62 salt = memoryview_to_bytes(salt) 

63 password = strtobytes(password) 

64 if digest=="des": 

65 from xpra.net.d3des import generate_response 

66 password = password.ljust(8, b"\x00")[:8] 

67 salt = salt.ljust(16, b"\x00")[:16] 

68 v = generate_response(password, salt) 

69 return hexstr(v) 

70 if digest in ("xor", "kerberos", "gss"): 

71 #kerberos and gss use xor because we need to use the actual token 

72 #at the other end 

73 salt = salt.ljust(len(password), b"\x00")[:len(password)] 

74 from xpra.buffers.cyxor import xor_str #@UnresolvedImport 

75 v = xor_str(password, salt) 

76 return memoryview_to_bytes(v) 

77 digestmod = get_digest_module(digest) 

78 if not digestmod: 

79 log("invalid digest module '%s'", digest) 

80 return None 

81 #warn_server_and_exit(EXIT_UNSUPPORTED, "server requested digest '%s' but it is not supported" % digest, "invalid digest") 

82 v = hmac.HMAC(password, salt, digestmod=digestmod).hexdigest() 

83 return v 

84 

85def verify_digest(digest, password, salt, challenge_response): 

86 if not password or not salt or not challenge_response: 

87 return False 

88 verify = gendigest(digest, password, salt) 

89 if not hmac.compare_digest(verify, challenge_response): 

90 log("expected '%s' but got '%s'", verify, challenge_response) 

91 return False 

92 return True 

93 

94 

95def get_salt(l=64): 

96 #too short: we would not feed enough random data to HMAC 

97 assert l>=32, "salt is too short: only %i bytes" % l 

98 #too long: limit the amount of random data we request from the system 

99 assert l<1024, "salt is too long: %i bytes" % l 

100 #all server versions support a client salt, 

101 #they also tell us which digest to use: 

102 return os.urandom(l)