VirtualMailManager/password.py
branchv0.7.x
changeset 636 27334cfc0c90
parent 633 8ea32fbfc9df
child 638 0de0b9e75c9f
equal deleted inserted replaced
635:54172669bbae 636:27334cfc0c90
    13         random_password = randompw()
    13         random_password = randompw()
    14         scheme, encoding = verify_scheme(scheme)
    14         scheme, encoding = verify_scheme(scheme)
    15         schemes, encodings = list_schemes()
    15         schemes, encodings = list_schemes()
    16 """
    16 """
    17 
    17 
       
    18 import hashlib
       
    19 
    18 from crypt import crypt
    20 from crypt import crypt
    19 from random import SystemRandom
    21 from random import SystemRandom
    20 from subprocess import Popen, PIPE
    22 from subprocess import Popen, PIPE
    21 
       
    22 try:
       
    23     import hashlib
       
    24 except ImportError:
       
    25     from VirtualMailManager.pycompat import hashlib
       
    26 
    23 
    27 from VirtualMailManager import ENCODING
    24 from VirtualMailManager import ENCODING
    28 from VirtualMailManager.emailaddress import EmailAddress
    25 from VirtualMailManager.emailaddress import EmailAddress
    29 from VirtualMailManager.common import get_unicode, version_str
    26 from VirtualMailManager.common import get_unicode, version_str
    30 from VirtualMailManager.constants import VMM_ERROR
    27 from VirtualMailManager.constants import VMM_ERROR
    31 from VirtualMailManager.errors import VMMError
    28 from VirtualMailManager.errors import VMMError
    32 
    29 
    33 COMPAT = hasattr(hashlib, 'compat')
       
    34 SALTCHARS = './0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
    30 SALTCHARS = './0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
    35 PASSWDCHARS = '._-+#*23456789abcdefghikmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ'
    31 PASSWDCHARS = '._-+#*23456789abcdefghikmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ'
    36 DEFAULT_B64 = (None, 'B64', 'BASE64')
    32 DEFAULT_B64 = (None, 'B64', 'BASE64')
    37 DEFAULT_HEX = (None, 'HEX')
    33 DEFAULT_HEX = (None, 'HEX')
    38 CRYPT_ID_MD5 = 1
    34 CRYPT_ID_MD5 = 1
    79     return hashed
    75     return hashed
    80 
    76 
    81 
    77 
    82 def _md4_new():
    78 def _md4_new():
    83     """Returns an new MD4-hash object if supported by the hashlib or
    79     """Returns an new MD4-hash object if supported by the hashlib or
    84     provided by PyCrypto - other `None`.
    80     provided by PyCrypto - otherwise `None`.
    85     """
    81     """
    86     try:
    82     try:
    87         return hashlib.new('md4')
    83         return hashlib.new('md4')
    88     except ValueError, err:
    84     except ValueError, err:
    89         if str(err) == 'unsupported hash type':
    85         if str(err) == 'unsupported hash type':
    90             if not COMPAT:
    86             try:
    91                 try:
    87                 from Crypto.Hash import MD4
    92                     from Crypto.Hash import MD4
    88                 return MD4.new()
    93                     return MD4.new()
    89             except ImportError:
    94                 except ImportError:
    90                 return None
    95                     return None
       
    96         else:
       
    97             raise
       
    98 
       
    99 
       
   100 def _sha256_new(data=''):
       
   101     """Returns a new sha256 object from the hashlib.
       
   102 
       
   103     Returns `None` if the PyCrypto in pycompat.hashlib is too old."""
       
   104     if not COMPAT:
       
   105         return hashlib.sha256(data)
       
   106     try:
       
   107         return hashlib.new('sha256', data)
       
   108     except ValueError, err:
       
   109         if str(err) == 'unsupported hash type':
       
   110             return None
       
   111         else:
    91         else:
   112             raise
    92             raise
   113 
    93 
   114 
    94 
   115 def _format_digest(digest, scheme, encoding):
    95 def _format_digest(digest, scheme, encoding):
   246     return _format_digest(digest, scheme, encoding)
   226     return _format_digest(digest, scheme, encoding)
   247 
   227 
   248 
   228 
   249 def _sha256_hash(password, scheme, encoding):
   229 def _sha256_hash(password, scheme, encoding):
   250     """Generates SHA256 hashes."""
   230     """Generates SHA256 hashes."""
   251     sha256 = _sha256_new(password)
   231     sha256 = hashlib.sha256(password)
   252     if sha256:
   232     if encoding in DEFAULT_B64:
   253         if encoding in DEFAULT_B64:
   233         digest = sha256.digest().encode('base64').rstrip()
   254             digest = sha256.digest().encode('base64').rstrip()
   234     else:
   255         else:
   235         digest = sha256.hexdigest()
   256             digest = sha256.hexdigest()
   236     return _format_digest(digest, scheme, encoding)
   257         return _format_digest(digest, scheme, encoding)
       
   258     return _dovecotpw(password, scheme, encoding)
       
   259 
   237 
   260 
   238 
   261 def _sha512_hash(password, scheme, encoding):
   239 def _sha512_hash(password, scheme, encoding):
   262     """Generates SHA512 hashes."""
   240     """Generates SHA512 hashes."""
   263     if not COMPAT:
   241     sha512 = hashlib.sha512(password)
   264         sha512 = hashlib.sha512(password)
   242     if encoding in DEFAULT_B64:
   265         if encoding in DEFAULT_B64:
   243         digest = sha512.digest().encode('base64').replace('\n', '')
   266             digest = sha512.digest().encode('base64').replace('\n', '')
   244     else:
   267         else:
   245         digest = sha512.hexdigest()
   268             digest = sha512.hexdigest()
   246     return _format_digest(digest, scheme, encoding)
   269         return _format_digest(digest, scheme, encoding)
       
   270     return _dovecotpw(password, scheme, encoding)
       
   271 
   247 
   272 
   248 
   273 def _smd5_hash(password, scheme, encoding):
   249 def _smd5_hash(password, scheme, encoding):
   274     """Generates SMD5 (salted PLAIN-MD5) hashes."""
   250     """Generates SMD5 (salted PLAIN-MD5) hashes."""
   275     md5 = hashlib.md5(password)
   251     md5 = hashlib.md5(password)
   294     return _format_digest(digest, scheme, encoding)
   270     return _format_digest(digest, scheme, encoding)
   295 
   271 
   296 
   272 
   297 def _ssha256_hash(password, scheme, encoding):
   273 def _ssha256_hash(password, scheme, encoding):
   298     """Generates SSHA256 (salted SHA256) hashes."""
   274     """Generates SSHA256 (salted SHA256) hashes."""
   299     sha256 = _sha256_new(password)
   275     sha256 = hashlib.sha256(password)
   300     if sha256:
   276     salt = _get_salt(SALTED_ALGO_SALT_LEN)
   301         salt = _get_salt(SALTED_ALGO_SALT_LEN)
   277     sha256.update(salt)
   302         sha256.update(salt)
   278     if encoding in DEFAULT_B64:
   303         if encoding in DEFAULT_B64:
   279         digest = (sha256.digest() + salt).encode('base64').rstrip()
   304             digest = (sha256.digest() + salt).encode('base64').rstrip()
   280     else:
   305         else:
   281         digest = sha256.hexdigest() + salt.encode('hex')
   306             digest = sha256.hexdigest() + salt.encode('hex')
   282     return _format_digest(digest, scheme, encoding)
   307         return _format_digest(digest, scheme, encoding)
       
   308     return _dovecotpw(password, scheme, encoding)
       
   309 
   283 
   310 
   284 
   311 def _ssha512_hash(password, scheme, encoding):
   285 def _ssha512_hash(password, scheme, encoding):
   312     """Generates SSHA512 (salted SHA512) hashes."""
   286     """Generates SSHA512 (salted SHA512) hashes."""
   313     if not COMPAT:
   287     salt = _get_salt(SALTED_ALGO_SALT_LEN)
   314         salt = _get_salt(SALTED_ALGO_SALT_LEN)
   288     sha512 = hashlib.sha512(password + salt)
   315         sha512 = hashlib.sha512(password + salt)
   289     if encoding in DEFAULT_B64:
   316         if encoding in DEFAULT_B64:
   290         digest = (sha512.digest() + salt).encode('base64').replace('\n', '')
   317             digest = (sha512.digest() + salt).encode('base64').replace('\n',
   291     else:
   318                                                                        '')
   292         digest = sha512.hexdigest() + salt.encode('hex')
   319         else:
   293     return _format_digest(digest, scheme, encoding)
   320             digest = sha512.hexdigest() + salt.encode('hex')
       
   321         return _format_digest(digest, scheme, encoding)
       
   322     return _dovecotpw(password, scheme, encoding)
       
   323 
   294 
   324 _scheme_info = {
   295 _scheme_info = {
   325     'CLEARTEXT': (_clear_hash, 0x10000f00),
   296     'CLEARTEXT': (_clear_hash, 0x10000f00),
   326     'CRAM-MD5': (_dovecotpw, 0x10000f00),
   297     'CRAM-MD5': (_dovecotpw, 0x10000f00),
   327     'CRYPT': (_crypt_hash, 0x10000f00),
   298     'CRYPT': (_crypt_hash, 0x10000f00),