diff --git a/roundup/password.py b/roundup/password.py
index 92ada54a1fa8756e2d62ad6e9d5580efcbcad3ad..006c591be99cf39f6960b973bd3b48b8fa68b023 100644 (file)
--- a/roundup/password.py
+++ b/roundup/password.py
import re, string, random
from base64 import b64encode, b64decode
-from roundup.anypy.hashlib_ import md5, sha1
+from roundup.anypy.hashlib_ import md5, sha1, shamodule
try:
import crypt
except ImportError:
#no m2crypto - make our own pbkdf2 function
from struct import pack
from hmac import HMAC
- try:
- from hashlib import sha1
- except ImportError:
- from sha import new as sha1
def xor_bytes(left, right):
"perform bitwise-xor of two byte-strings"
def _pbkdf2(password, salt, rounds, keylen):
digest_size = 20 # sha1 generates 20-byte blocks
total_blocks = int((keylen+digest_size-1)/digest_size)
- hmac_template = HMAC(password, None, sha1)
+ hmac_template = HMAC(password, None, shamodule)
out = _bempty
for i in xrange(1, total_blocks+1):
hmac = hmac_template.copy()
raw_salt = h64decode(salt)
return rounds, salt, raw_salt, digest
-def encodePassword(plaintext, scheme, other=None):
+def encodePassword(plaintext, scheme, other=None, config=None):
"""Encrypt the plaintext password.
"""
if plaintext is None:
else:
raw_salt = getrandbytes(20)
salt = h64encode(raw_salt)
- #FIXME: find way to access config, so default rounds
- # can be altered for faster/slower hosts via config.ini
- rounds = 10000
+ if config:
+ rounds = config.PASSWORD_PBKDF2_DEFAULT_ROUNDS
+ else:
+ rounds = 10000
if rounds < 1000:
raise PasswordValueError, "invalid PBKDF2 hash (rounds too low)"
raw_digest = pbkdf2(plaintext, raw_salt, rounds, 20)
"""
#TODO: code to migrate from old password schemes.
- known_schemes = [ "PBKDF2", "SHA", "MD5", "crypt", "plaintext" ]
+ deprecated_schemes = ["SHA", "MD5", "crypt", "plaintext"]
+ known_schemes = ["PBKDF2"] + deprecated_schemes
- def __init__(self, plaintext=None, scheme=None, encrypted=None, strict=False):
+ def __init__(self, plaintext=None, scheme=None, encrypted=None, strict=False, config=None):
"""Call setPassword if plaintext is not None."""
if scheme is None:
scheme = self.default_scheme
if plaintext is not None:
- self.setPassword (plaintext, scheme)
+ self.setPassword (plaintext, scheme, config=config)
elif encrypted is not None:
- self.unpack(encrypted, scheme, strict=strict)
+ self.unpack(encrypted, scheme, strict=strict, config=config)
else:
self.scheme = self.default_scheme
self.password = None
""" Password has insecure scheme or other insecure parameters
and needs migration to new password scheme
"""
- if self.scheme != 'PBKDF2':
+ if self.scheme in self.deprecated_schemes:
return True
rounds, salt, raw_salt, digest = pbkdf2_unpack(self.password)
if rounds < 1000:
return True
return False
- def unpack(self, encrypted, scheme=None, strict=False):
+ def unpack(self, encrypted, scheme=None, strict=False, config=None):
"""Set the password info from the scheme:<encryted info> string
(the inverse of __str__)
"""
self.plaintext = None
else:
# currently plaintext - encrypt
- self.setPassword(encrypted, scheme)
+ self.setPassword(encrypted, scheme, config=config)
if strict and self.scheme not in self.known_schemes:
raise PasswordValueError, "unknown encryption scheme: %r" % (self.scheme,)
- def setPassword(self, plaintext, scheme=None):
+ def setPassword(self, plaintext, scheme=None, config=None):
"""Sets encrypts plaintext."""
if scheme is None:
scheme = self.default_scheme
self.scheme = scheme
- self.password = encodePassword(plaintext, scheme)
+ self.password = encodePassword(plaintext, scheme, config=config)
self.plaintext = plaintext
def __str__(self):