Package web2py :: Package gluon :: Module utils

[hide private]
[frames] | no frames]

# Source Code for Module web2py.gluon.utils

      1  #!/usr/bin/env python
      2  # -*- coding: utf-8 -*-
      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
     22 -def md5_hash(text):
     23      """ Generate a md5 hash with the given text """
     24      return hashlib.md5(text).hexdigest()
     25
     26 -def simple_hash(text, digest_alg = 'md5'):
     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
     40 -def get_digest(value):
     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  ### compute constant ctokens
     73 -def initialize_urandom():
     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              # try to add process-specific entropy
     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              # works anyway
    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
    110 -def web2py_uuid():
    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)] # use /dev/urandom if possible
    121          bytes = [bytes[i] ^ ubytes[i] for i in range(16)]
    122      except NotImplementedError:
    123          pass
    124      ## xor bytes with constant ctokens
    125      bytes = ''.join(chr(c ^ ctokens[i]) for i,c in enumerate(bytes))
    126      return str(uuid.UUID(bytes=bytes, version=4))
    127