1
2
3
4 """
5 This file is part of the web2py Web Framework
6 Copyrighted by Massimo Di Pierro <mdipierro@cs.depaul.edu>
7 License: LGPLv3 (http://www.gnu.org/licenses/lgpl.html)
8
9 This file specifically includes utilities for security.
10 """
11
12 import hashlib
13 import hmac
14 import uuid
15 import random
16 import time
17 import os
18 import logging
19
20 logger = logging.getLogger("web2py")
21
23 """ Generate a md5 hash with the given text """
24 return hashlib.md5(text).hexdigest()
25
27 """
28 Generates hash with the given text using the specified
29 digest hashing algorithm
30 """
31 if not digest_alg:
32 raise RuntimeError, "simple_hash with digest_alg=None"
33 elif not isinstance(digest_alg,str):
34 h = digest_alg(text)
35 else:
36 h = hashlib.new(digest_alg)
37 h.update(text)
38 return h.hexdigest()
39
41 """
42 Returns a hashlib digest algorithm from a string
43 """
44 if not isinstance(value,str):
45 return value
46 value = value.lower()
47 if value == "md5":
48 return hashlib.md5
49 elif value == "sha1":
50 return hashlib.sha1
51 elif value == "sha224":
52 return hashlib.sha224
53 elif value == "sha256":
54 return hashlib.sha256
55 elif value == "sha384":
56 return hashlib.sha384
57 elif value == "sha512":
58 return hashlib.sha512
59 else:
60 raise ValueError("Invalid digest algorithm")
61
62 -def hmac_hash(value, key, digest_alg='md5', salt=None):
63 if ':' in key:
64 digest_alg, key = key.split(':')
65 digest_alg = get_digest(digest_alg)
66 d = hmac.new(key,value,digest_alg)
67 if salt:
68 d.update(str(salt))
69 return d.hexdigest()
70
71
72
74 """
75 This function and the web2py_uuid follow from the following discussion:
76 http://groups.google.com/group/web2py-developers/browse_thread/thread/7fd5789a7da3f09
77
78 At startup web2py compute a unique ID that identifies the machine by adding
79 uuid.getnode() + int(time.time() * 1e3)
80
81 This is a 48-bit number. It converts the number into 16 8-bit tokens.
82 It uses this value to initialize the entropy source ('/dev/urandom') and to seed random.
83
84 If os.random() is not supported, it falls back to using random and issues a warning.
85 """
86 node_id = uuid.getnode()
87 microseconds = int(time.time() * 1e6)
88 ctokens = [((node_id + microseconds) >> ((i%6)*8)) % 256 for i in range(16)]
89 random.seed(node_id + microseconds)
90 try:
91 os.urandom(1)
92 try:
93
94 frandom = open('/dev/urandom','wb')
95 try:
96 frandom.write(''.join(chr(t) for t in ctokens))
97 finally:
98 frandom.close()
99 except IOError:
100
101 pass
102 except NotImplementedError:
103 logger.warning(
104 """Cryptographically secure session management is not possible on your system because
105 your system does not provide a cryptographically secure entropy source.
106 This is not specific to web2py; consider deploying on a different operating system.""")
107 return ctokens
108 ctokens = initialize_urandom()
109
111 """
112 This function follows from the following discussion:
113 http://groups.google.com/group/web2py-developers/browse_thread/thread/7fd5789a7da3f09
114
115 It works like uuid.uuid4 except that tries to use os.urandom() if possible
116 and it XORs the output with the tokens uniquely associated with this machine.
117 """
118 bytes = [random.randrange(256) for i in range(16)]
119 try:
120 ubytes = [ord(c) for c in os.urandom(16)]
121 bytes = [bytes[i] ^ ubytes[i] for i in range(16)]
122 except NotImplementedError:
123 pass
124
125 bytes = ''.join(chr(c ^ ctokens[i]) for i,c in enumerate(bytes))
126 return str(uuid.UUID(bytes=bytes, version=4))
127