def check1(pw): pw_ent_bits = password_strength(pw)['entropy'] result = get_pos_typos(pw, pw_ent_bits, 290729) result.sort(key=lambda x: x[1], reverse=True) print "len:{}".format(len(result)) for (typ, pp) in result: print("typo:{}, pp:{}, strength:{}".format( typ, pp, password_strength(typ)['entropy']))
def __call__(self, node, value): request = node.bindings.get('request') localizer = get_localizer(request) settings = request.registry.settings value = value.replace(" ", "") password_min_entropy = int(settings.get('password_entropy', 60)) # We accept a 10% of variance in password_min_entropy because # we have calculated the entropy by javascript too and the results # may vary. password_min_entropy = (0.90 * password_min_entropy) generated_password = request.session.get('last_generated_password', '') if len(generated_password) > 0 and generated_password == value: # Don't validate the password if it is the generated password # That is, the user has filled out the form with the suggested # password return # Get a users e-mail addresses to make sure a user does not use one of those as password user = get_session_user(request, raise_on_not_logged_in = False) if not user: # User is resetting a forgotten password hash_code = request.matchdict['code'] password_reset = request.db.reset_passwords.find_one({'hash_code': hash_code}) user = request.userdb_new.get_user_by_mail(password_reset['email']) mail_addresses = [item.email for item in user.mail_addresses.to_list()] veredict = zxcvbn.password_strength(value, user_inputs=mail_addresses) if veredict.get('entropy', 0) < password_min_entropy: err = _('The password complexity is too weak.') raise colander.Invalid(node, localizer.translate(err))
def validate_password(self, _, password): """Validate the password if this is valid.""" password_entropy = zxcvbn.password_strength(password)['entropy'] if password_entropy < 20: raise ValidationError("Password too weak") password_hash = pwd_context.encrypt(password) return password_hash
def __post_recovery(self, **post): try: data = Bunch(reset_password_form.native(post)[0]) except Exception as e: if config.get('debug', False): raise return 'json:', dict(success=False, message=_("Unable to parse data."), data=post, exc=str(e)) recovery = self.__get_recovery(data.email, data.recovery_key) if not recovery: return 'json:', dict(success=False, message=_("Sorry that recovery link has already expired"), location="/account/recover") passwd_ok, error_msg = _check_password(data.password, data.pass2) if not passwd_ok: return 'json:', dict(success=False, message=error_msg) #If the password isn't strong enough, reject it if(zxcvbn.password_strength(data.password).get("score") < MINIMUM_PASSWORD_STRENGTH): return 'json:', dict(success=False, message=_("Password provided is too weak. please add more characters, or include lowercase, uppercase, and special characters."), data=data) #set new password user = recovery.user user.password = data.password user.save() #remove recovery key recovery.delete() authenticate(user.username, data.password) return 'json:', dict(success=True, message=_("Password changed, forwarding ..."), location="/")
def collect_parameters(self): """Generate report :return: generator of progress: number of checks done """ if self.dontcheck: raise ServerException("Dontcheck is set for %s" % self) logger.debug("Start collecting parameters for %s" % self) if not self.accessible(): self.param_check_status = "server is not accessible" self.parameters = {} return else: self.param_check_status = "in progress" try: for result in self.rolecollection.collect_parameters(self.param_cmd, self.param_script): self.param_check_status = "in progress, %s checks" % result['progress'] self.parameters = result['parameters'] self.param_failures = result['failures'] self.param_check_time = time.time() yield result['progress'] except ServerException as se: self.param_check_status = "FAILED with ServerException: %s" % se self.parameters = {} else: if 'password' in self.account: self.parameters['password_strength'] = password_strength( self.account['password'], user_inputs=[])['score'] else: self.parameters['password_strength'] = 4 self.param_check_status = "finished"
def __process_passwords(passwords): out = [] for p, users in passwords: out.append(__coloured_score(zxcvbn.password_strength(p)["score"], p)) return ", ".join(out)
def post(self, **post): try: data = Bunch(register_form.native(post)[0]) except Exception as e: if config.get('debug', False): raise return 'json:', dict(success=False, message=_("Unable to parse data."), data=post, exc=str(e)) if not data.username or not data.email or not data.password or data.password != data.pass2: return 'json:', dict(success=False, message=_("Missing data or passwords do not match."), data=data) #Make sure that the provided email address is a valid form for an email address v = EmailValidator() email = data.email email, err = v.validate(email) if err: return 'json:', dict(success=False, message=_("Invalid email address provided."), data=data) #If the password isn't strong enough, reject it if(zxcvbn.password_strength(data.password).get("score") < MINIMUM_PASSWORD_STRENGTH): return 'json:', dict(success=False, message=_("Password provided is too weak. please add more characters, or include lowercase, uppercase, and special characters."), data=data) #Ensures that the provided username and email are lowercase user = User(data.username.lower(), data.email.lower(), active=True) user.password = data.password try: user.save() except ValidationError: return 'json:', dict(success=False, message=_("Invalid email address provided."), data=data) except NotUniqueError: return 'json:', dict(success=False, message=_("Either the username or email address provided is already taken."), data=data) authenticate(user.username, data.password) return 'json:', dict(success=True, location="/")
def eval_passwords(self, data): strength_results = {} for row in data: pass_check = zxcvbn.password_strength(row[2]) # Remove the password from the results del pass_check['password'] strength_results[row[0]] = pass_check return strength_results
def clean_key(self): # Password strength testing mostly done in JS; minimal validation here. password = self.cleaned_data.get('key') results = password_strength(password) if results['entropy'] < settings.PASSWORD_MINIMUM_ENTROPY: raise forms.ValidationError("Your password isn't strong enough.") return password
def all_passwords(self): results = self.table.search((Query().password.exists()) & (Query().password != "") & self.only_users & self.only_enabled) return [(result["password"], zxcvbn.password_strength(result["password"])["score"]) for result in results]
def post(self, **post): try: data = Bunch(register_form.native(post)[0]) except Exception as e: if config.get('debug', False): raise return 'json:', dict(success=False, message=_("Unable to parse data."), data=post, exc=str(e)) if not data.username or not data.email or not data.password or data.password != data.pass2: return 'json:', dict( success=False, message=_("Missing data or passwords do not match."), data=data) #Make sure that the provided email address is a valid form for an email address v = EmailValidator() email = data.email email, err = v.validate(email) if err: return 'json:', dict(success=False, message=_("Invalid email address provided."), data=data) #If the password isn't strong enough, reject it if (zxcvbn.password_strength(data.password).get("score") < MINIMUM_PASSWORD_STRENGTH): return 'json:', dict( success=False, message= _("Password provided is too weak. please add more characters, or include lowercase, uppercase, and special characters." ), data=data) #Ensures that the provided username and email are lowercase user = User(data.username.lower(), data.email.lower(), active=True) user.password = data.password try: user.save() except ValidationError: return 'json:', dict(success=False, message=_("Invalid email address provided."), data=data) except NotUniqueError: return 'json:', dict( success=False, message= _("Either the username or email address provided is already taken." ), data=data) authenticate(user.username, data.password) return 'json:', dict(success=True, location="/")
def __init__(self, password='', username=''): if args.basic: self.basic = BasicAnalysis(password) self.basic.categorize(username) if args.zxcvbn: try: self.zxcvbn = zxcvbn.password_strength(password) #save memory on objects we dont use self.zxcvbn = {"crack_time":self.zxcvbn["crack_time"], "score":self.zxcvbn["score"]} except OverflowError: raise OverflowError #pass it back down, and we'll ignore this one.
def valid_new_password(password, confirmation): strength = password_strength(password) if password != confirmation: flash('Password confirmation differs from new password.', 'danger') return False elif strength['score'] <= 2: flash('New password is too weak. Estimated cracking time is {}.'.format(strength['crack_time_display']), 'danger') return False return True
def run(db, args): total, local_users, domain_users, computers = db.counts print("cracke-dit report for {}\n".format(args.domain)) print("Local / Domain users:\t{}/{}".format(local_users, domain_users)) if not args.only_enabled: print("Enabled / disabled users:\t{}/{}".format(*db.user_counts)) if not args.only_users: print("Computer accounts:\t{}\t{:.2f}%".format(computers, (computers / total) * 100)) cracked, blank, historic = db.password_stats print("Passwords cracked:\t{}/{}\t{:.2f}%".format(cracked, total, (cracked / total) * 100)) print("Historic passwords:\t{}\t{:.2f}%".format(historic, (historic / total) * 100)) only_alpha, with_special, only_digits = db.password_composition_stats print(UNDERLINE + "\nPassword composition" + END) print("Only alphanumeric:\t{}\t{:.2f}%".format(only_alpha, (only_alpha / total) * 100)) print("Only digits:\t{}\t{:.2f}%".format(only_digits, (only_digits / total) * 100)) print("With 'special char':\t{}\t{:.2f}%".format(with_special, (with_special / total) * 100)) headers = ["Password", "Length", "Count", "Score", "Pwned #", "Users"] fmt_lambda = lambda password, count, score, users: [password, len(password), count, __coloured_score(score), __get_usage(password) if not args.no_hibp else '', __process_users(users)] default_align = [">", "<", "<", "<", "<", ""] top_passwords = db.get_passwords(sortby=lambda (password, count, score, users): (count, score, len(password)), reverse=True, limit=args.limit) __print_table(title="Top {} Passwords (by use, score)".format(args.limit), headers=headers, align=default_align, values=top_passwords, format=fmt_lambda) bad_pass = db.get_passwords(sortby=lambda (password, count, score, users): (zxcvbn.password_strength(password)["score"], len(password), len(users)), reverse=False, limit=args.limit) __print_table(title="Top {} Worst Passwords (by score, length)".format(args.limit), headers=headers, align=default_align, values=bad_pass, format=fmt_lambda) passwords = db.get_passwords_where(lambda password: password != "") __graph_passwords_containing("Passwords containing months", passwords, OrderedDict([(calendar.month_name[m], 0) for m in range(1, 13)])) __graph_passwords_containing("Passwords containing days", passwords, OrderedDict([(calendar.day_name[d], 0) for d in range(0, 7)])) print(UNDERLINE + "\nPassword length distribution" + END) grpd_passwords = ((p, len(list(count))) for p, count in itertools.groupby(sorted(passwords, key=lambda r: len(r["password"])), lambda r: len(r["password"]))) keys, vals = map(list, zip(*grpd_passwords)) vals_percents = [" ({:.2f}%)".format((v / total) * 100) for v in vals] __print_graph(keys, vals, vals_percents) if historic > 0: __print_table(title="Users historic passwords (top {})".format((args.limit)), headers=[" User ", "# Passwords", "Passwords"], align=[">", "<", ""], values=db.get_historic_passwords(args.limit), format=lambda user, passwords: [user, len(passwords), __process_passwords(passwords)])
def get_passwords(self, sortby, reverse=True, limit=10): results = sorted( self.table.search((Query().password.exists()) & self.only_users & self.only_enabled), key=lambda r: r["password"]) passwords = ((password, len(list(count))) for password, count in itertools.groupby( results, lambda r: r["password"])) return sorted(list( (password, count, zxcvbn.password_strength(password)["score"], self.__get_users_with_password(password)) for password, count in passwords), key=sortby, reverse=reverse)[:limit]
def entropy(self, **query): # Remove the timestamp query.pop('ts', None) # Make sure the user provides only a password if set(query.keys()) - {'password'}: raise HTTPForbidden() password = query.get("password") strong = False # If the password has a score of greater than 2, allow it if(zxcvbn.password_strength(password).get("score") > 2): strong = True return 'json:', dict(approved=strong, query={str(k): v for k, v in query.items()})
def entropy(self, **query): #Remove the timestamp query.pop('ts', None) #Make sure the user provides only a password if set(query.keys()) - {'password'}: raise HTTPForbidden() password = query.get("password") strong = False #If the password has a score of greater than 2, allow it if (zxcvbn.password_strength(password).get("score") > 2): strong = True return 'json:', dict(approved=strong, query={str(k): v for k, v in query.items()})
def validate(self, data): """Make sure the passwords match and are reasonably strong.""" password = data['password'] password2 = data['password2'] if password != password2: raise serializers.ValidationError("Passwords do not match.") pw_results = zxcvbn.password_strength(password) strength = pw_results['score'] if strength < settings.PASSWORD_STRENGTH_MIN: raise serializers.ValidationError( "Insufficient password strength. Scored {}/4. " "Estimated time to crack: {}".format( strength, pw_results['crack_time_display'])) return data
def password_score(self): """ This function calculates scores of strength of password. Returns: Float. Scores from 0 to 100. """ password = self.data.get('password') or '' min_length = self.fields['password'].min_length if len(password) < min_length: return len(password) * PASSWORD_LENGTH_BORDER_SCORE / min_length strength = password_strength(password)['crack_time'] strength = math.log10(strength) max_strength = math.log10(PASSWORD_MAX_STRENGTH) strength = min(strength, max_strength) strength = max(strength, 0) initial_scores = PASSWORD_LENGTH_BORDER_SCORE max_score = PASSWORD_MAX_SCORE - PASSWORD_LENGTH_BORDER_SCORE return initial_scores + strength * max_score / max_strength
def __call__(self, node, value): request = node.bindings.get('request') localizer = get_localizer(request) settings = request.registry.settings value = value.replace(" ", "") password_min_entropy = int(settings.get('password_entropy', 60)) # We accept a 10% of variance in password_min_entropy because # we have calculated the entropy by javascript too and the results # may vary. password_min_entropy = (0.90 * password_min_entropy) generated_password = request.session.get('last_generated_password', '') if len(generated_password) > 0 and generated_password == value: # Don't validate the password if it is the generated password # That is, the user has filled out the form with the suggested # password return # Get a users e-mail addresses to make sure a user does not use one of those as password user = get_session_user(request, raise_on_not_logged_in=False) if not user: # User is resetting a forgotten password hash_code = request.matchdict['code'] password_reset = request.db.reset_passwords.find_one( {'hash_code': hash_code}) if password_reset.get('eppn'): user = request.userdb_new.get_user_by_eppn( password_reset['eppn']) # Legacy password reset codes were connected to the user by email elif password_reset.get('email'): user = request.userdb_new.get_user_by_mail( password_reset['email']) mail_addresses = [item.email for item in user.mail_addresses.to_list()] veredict = zxcvbn.password_strength(value, user_inputs=mail_addresses) if veredict.get('entropy', 0) < password_min_entropy: err = _('The password complexity is too weak.') raise colander.Invalid(node, localizer.translate(err))
def _get_good_password(self, user): password1 = self.grab("Password: "******"Password (again): ", True) if password2 != password1: self.error("Passwords do not match, try again.") return None blacklist = [ user.username, user.first_name, user.last_name, ] check = zxcvbn.password_strength(password1, blacklist) if check['score'] < self.PASSWORD_MIN_SCORE: self.error("Password is too weak (bruteforce: %s)", check['crack_time_display']) return None self.success("Password is strong enough (bruteforce: %s)", check['crack_time_display']) return password1
def __post_recovery(self, **post): try: data = Bunch(reset_password_form.native(post)[0]) except Exception as e: if config.get('debug', False): raise return 'json:', dict(success=False, message=_("Unable to parse data."), data=post, exc=str(e)) recovery = self.__get_recovery(data.email, data.recovery_key) if not recovery: return 'json:', dict( success=False, message=_("Sorry that recovery link has already expired"), location="/account/recover") passwd_ok, error_msg = _check_password(data.password, data.pass2) if not passwd_ok: return 'json:', dict(success=False, message=error_msg) #If the password isn't strong enough, reject it if (zxcvbn.password_strength(data.password).get("score") < MINIMUM_PASSWORD_STRENGTH): return 'json:', dict( success=False, message= _("Password provided is too weak. please add more characters, or include lowercase, uppercase, and special characters." ), data=data) #set new password user = recovery.user user.password = data.password user.save() #remove recovery key recovery.delete() authenticate(user.username, data.password) return 'json:', dict(success=True, message=_("Password changed, forwarding ..."), location="/")
def set_password(self, new_password): if settings.USE_LDAP: import ldap l = ldap.initialize(settings.LDAP_HOST) l.set_option(ldap.OPT_REFERRALS, 0) l.set_option(ldap.OPT_PROTOCOL_VERSION, 3) l.simple_bind_s(settings.LDAP_BIND_DN, settings.LDAP_BIND_PASS) dn = 'uid=%s,%s' % (self.user.username, settings.LDAP_SEARCH_PATH) l.passwd_s(dn, None, new_password) self.user.set_password(new_password) self.user.save() pws = password_strength(new_password) self.password_entropy = pws['entropy'] self.password_score = pws['score'] self.password_updated = datetime.now() self.password_force_change = False self.password_recovery_token = None self.save()
def entropy(self): if self.cache.get('entropy') is not None: return self.cache['entropy'] if not self.string: return 0 if len(self.string) > 100: check_str = self.string[:100] else: check_str = self.string try: entropy = zxcvbn.password_strength(check_str)['entropy'] except UnicodeDecodeError: logger.warning( 'Failed to get entropy due to unicode decode error.') entropy = 0 except OverflowError: logger.warning('Failed to get entropy due to overflow error.') entropy = 0 self.cache['entropy'] = entropy return self.cache['entropy']
def create_trie_only(): passwords_path = MAIN_DIR + 'rockyou-ascii.txt' # for quick checks #passwords_path = MAIN_DIR + 'rockyou-ascii_3.txt' ## # another_trie_path = MAIN_DIR + 'myTrieYay.txt' all_names = [] with open(passwords_path, 'rb') as ff: with open(TRIE_PATH, 'wb') as ww: # at the end of the file the format is broken. simply deleted it manually START = time() print("start:{}".format(START)) #for line in all_data: # for line in ff: try: tup = (line.split()) count = int(tup[0]) splitted_str = [x for x in tup[1:]] pw = ' '.join(splitted_str) pw_ent_bits = password_strength(pw)['entropy'] all_names.append(pw) typos = [ tt[0] for tt in get_pos_typos(pw, pw_ent_bits, 1, NNN) ] all_names = all_names + typos except UnicodeError as e: # shouldn't happen because the file manipulation is done before print "line: {}".format(line) raise e except ValueError as e: # password contains space so split fails print "line: {}".format(line) raise e except KeyError as e: print("KeyError") raise e print "finished collecting" all_for_trie = marisa_trie.Trie(all_names) print "trie createed writing to file" all_for_trie.save(another_trie_path) for word, code in all_for_trie.items(): ww.write(" ".join([str(code), str(word), '\n']))
def main(argv={}): password = Password(argv).generate() """ Copy the password to clipboard? """ if not argv['--no-clipboard']: try: import xerox xerox.copy(password) except ImportError: print no_xerox_error """ Print the password? """ if argv['--print'] or argv['--no-clipboard']: print password """ Print password strength """ try: from zxcvbn import password_strength strength = password_strength(password) print 'crack time: %s, score: %s out of 4' % (strength['crack_time_display'], str(strength['score'])) except ImportError: print no_zxcvbn_error
def entropy(self): if self.cache.get('entropy') is not None: return self.cache['entropy'] if not self.string: return 0 if len(self.string) > 100: check_str = self.string[:100] else: check_str = self.string try: entropy = zxcvbn.password_strength(check_str)['entropy'] except UnicodeDecodeError: logger.warning( 'Failed to get entropy due to unicode decode error.' ) entropy = 0 except OverflowError: logger.warning( 'Failed to get entropy due to overflow error.' ) entropy = 0 self.cache['entropy'] = entropy return self.cache['entropy']
def __call__(self, node, value): request = node.bindings.get('request') localizer = get_localizer(request) settings = request.registry.settings value = value.replace(" ", "") password_min_entropy = int(settings.get('password_entropy', 60)) # We accept a 10% of variance in password_min_entropy because # we have calculated the entropy by javascript too and the results # may vary. password_min_entropy = (0.90 * password_min_entropy) generated_password = request.session.get('last_generated_password', '') if len(generated_password) > 0 and generated_password == value: # Don't validate the password if it is the generated password # That is, the user has filled out the form with the suggested # password return veredict = zxcvbn.password_strength(value) if veredict.get('entropy', 0) < password_min_entropy: err = _('The password complexity is too weak.') raise colander.Invalid(node, localizer.translate(err))
def test_password_strength(password, user_inputs=None): '''Wrapper around zxcvbn.password_strength''' result = zxcvbn.password_strength(password, user_inputs) result['feedback'] = get_feedback(result['score'], result['match_sequence']) return result
def zxcvbn_getpass(prompt, prefix='', allow_empty=True): """ Similar to getpass.getpass, but shows password strength while typing """ pw = None current = '' checked_strength_of = None prompt_offset = len(prefix) + len(prompt) purge_stdin() sys.stderr.write('\033[1G\033[K') sys.stderr.write(prefix + prompt) sys.stderr.flush() interacted = False with raw_mode(): while True: if interacted and not pw and checked_strength_of != current: strength = zxcvbn.password_strength(current) checked_strength_of = current text = '%-4s %3sb %s' % (strength['score'] * '*', int(strength['entropy']), strength['crack_time_display']) sys.stderr.write('\033[55G\033[K%s\033[%sG' % (text, prompt_offset + 1)) sys.stderr.flush() c = sys.stdin.read(1) interacted = True if c == '\r' or c == '\n': if not current and not pw: if allow_empty: sys.stderr.write('\033[K\n') sys.stderr.flush() return None sys.stderr.write('\033[1G\033[K') new_prompt = prefix + 'No password given. Retry: ' sys.stderr.write(new_prompt) prompt_offset = len(new_prompt) sys.stderr.flush() interacted = False continue if pw: if pw != current: sys.stderr.write('\033[1G\033[K') new_prompt = prefix + 'Passwords did not match. Retry: ' sys.stderr.write(new_prompt) prompt_offset = len(new_prompt) sys.stderr.flush() pw = None current = '' interacted = False continue sys.stderr.write('\033[K\n') sys.stderr.flush() return pw pw = current current = '' sys.stderr.write('\033[1G\033[K') new_prompt = prefix + 'Repeat to verify: ' sys.stderr.write(new_prompt) prompt_offset = len(new_prompt) sys.stderr.flush() elif c in string.printable: current += c elif c == '\x17': # C-w current = current[:current.rfind(' ', 0, -1) + 1] elif c == '\x15': # C-u current = '' elif c == '\x7f': # backspace current = current[:-1] elif c == '\x03': # C-c raise KeyboardInterrupt else: sys.stderr.write('\033[55G\033[Kignored key %r\033[%sG' % (c, prompt_offset + 1)) sys.stderr.flush()
def entropy(w): try: return password_strength(w)['entropy'] except Exception as e: print (e) return -1
def zxcvbn_getpass(prompt, prefix='', allow_empty=True): """ Similar to getpass.getpass, but shows password strength while typing """ pw = None current = '' checked_strength_of = None prompt_offset = len(prefix) + len(prompt) purge_stdin() sys.stderr.write('\033[1G\033[K') sys.stderr.write(prefix + prompt) sys.stderr.flush() interacted = False with raw_mode(): while True: if interacted and not pw and checked_strength_of != current: strength = zxcvbn.password_strength(current) checked_strength_of = current text = '%-4s %3sb %s' % (strength['score'] * '*', int(strength['entropy']), strength['crack_time_display']) sys.stderr.write('\033[55G\033[K%s\033[%sG' % ( text, prompt_offset + 1)) sys.stderr.flush() c = sys.stdin.read(1) interacted = True if c == '\r' or c == '\n': if not current and not pw: if allow_empty: sys.stderr.write('\033[K\n') sys.stderr.flush() return None sys.stderr.write('\033[1G\033[K') new_prompt = prefix+'No password given. Retry: ' sys.stderr.write(new_prompt) prompt_offset = len(new_prompt) sys.stderr.flush() interacted = False continue if pw: if pw != current: sys.stderr.write('\033[1G\033[K') new_prompt = prefix+'Passwords did not match. Retry: ' sys.stderr.write(new_prompt) prompt_offset = len(new_prompt) sys.stderr.flush() pw = None current = '' interacted = False continue sys.stderr.write('\033[K\n') sys.stderr.flush() return pw pw = current current = '' sys.stderr.write('\033[1G\033[K') new_prompt = prefix + 'Repeat to verify: ' sys.stderr.write(new_prompt) prompt_offset = len(new_prompt) sys.stderr.flush() elif c in string.printable: current += c elif c == '\x17': # C-w current = current[:current.rfind(' ', 0, -1)+1] elif c == '\x15': # C-u current = '' elif c == '\x7f': # backspace current = current[:-1] elif c == '\x03': # C-c raise KeyboardInterrupt else: sys.stderr.write('\033[55G\033[Kignored key %r\033[%sG' % ( c, prompt_offset + 1)) sys.stderr.flush()
def get_pos_typos(pw, pw_ent_bits, count=1, req_len=0): if not pw: return [] # TODO CHANGE pw_press = TO_KEY_SEQ(pw) # caps lock on/off p_caps = 10.9 p_shift_first = 4.5 # flipped, either on or off p_added_end = 4.6 p_added_front = 1.3 p_shift_last = 0.2 p_prox = 21.8 # out of 100 sum_p = p_caps + p_shift_first + p_added_front + p_added_end + p_shift_last + p_prox # sum_p -= p_added_front # p_caps = (count * p_caps) / sum_p p_shift_first = (count * p_shift_first) / sum_p p_added_end = (count * p_added_end) / sum_p #p_added_front = (count * p_added_front) / sum_p p_shift_last = (count * p_shift_last) / sum_p p_prox = (count * p_prox) / sum_p # # small_sum = p_caps+p_shift_first + p_added_end + p_shift_last + p_prox ## TODO REMOVE # print "initial sum: {}".format(small_sum) ## TODO REMOVE many_typos = [] try: t_caps = ''.join([CAPS, pw_press ]) if pw_press[0] != CAPS else pw_press[1:] t_shift_first = ''.join([SHIFT, pw_press ]) if pw_press[0] != SHIFT else pw_press[1:] t_shift_last = ''.join([ pw_press[:-1], SHIFT, pw_press[-1] ]) if pw_press[-2] != SHIFT else ''.join([pw_press[:-2], pw_press[-1]]) tmp_typo_list = [(t_caps, p_caps), (t_shift_last, p_shift_last), (t_shift_first, p_shift_first)] except IndexError as e: print "skipped steps for {}. Index Error".format(pw) # for (typo, pp) in tmp_typo_list: typo = BACK_TO_WORD(typo) ### typo_ent_bits = password_strength(typo)['entropy'] ### too_weak = (typo_ent_bits < MIN_ENT) or ( (typo_ent_bits - pw_ent_bits) < MIN_REL_ENT) ### if too_weak: continue many_typos.append((typo, pp)) # added end - only digits zero = ord('0') for i in xrange(0, 10): add_ch = chr(i + zero) typo = BACK_TO_WORD(''.join([pw_press, add_ch])) typo_ent_bits = password_strength(typo)['entropy'] ### too_weak = (typo_ent_bits < MIN_ENT) or ( (typo_ent_bits - pw_ent_bits) < MIN_REL_ENT) ### if too_weak: continue many_typos.append((typo, p_added_end / 10)) # addedFront - TODO # prox length = len(pw_press) # print length for i in xrange(length): c = pw_press[i] nearby_chrs = filter(lambda x: not UPPER(x), list(NEARBY_KEYS(c))) nearby_len = len(nearby_chrs) if not nearby_len: continue each_p = (1.0 / length) * p_prox * (1.0 / nearby_len) for c_t in nearby_chrs: typo = BACK_TO_WORD(''.join([pw_press[:i], c_t, pw_press[i + 1:]])) typo_ent_bits = password_strength(typo)['entropy'] ### too_weak = (typo_ent_bits < MIN_ENT) or ( (typo_ent_bits - pw_ent_bits) < MIN_REL_ENT) ### if too_weak: continue many_typos.append((typo, each_p)) # getting only the top length typos try: if req_len: sum_prob_of_req = 0 ii = min(req_len, len(many_typos)) - 1 least_p = many_typos[ii][1] m_t_len = len(many_typos) while (ii < m_t_len) and (many_typos[ii][1] == least_p): ii += 1 req_typos = many_typos[:ii] for jj in xrange(ii): sum_prob_of_req += req_typos[jj][1] assert sum_prob_of_req < 1.0000001 # there's a bit of miss-accuracy with float sums # if sum_prob_of_req > 1.000000001: ###### there's a bit of miss-accuracy with float sums # print 'prob_sum:', sum_prob_of_req # print "bool:", sum_prob_of_req > 1.0 # print "pw '{}'' with too much prob, {} ".format(pw,sum_prob_of_req) # for ttt in req_typos: # print ttt for jj in xrange(len(req_typos)): tt, tt_pp = req_typos[jj] req_typos[jj] = (tt, tt_pp / sum_prob_of_req) except IndexError as e: print "req_L: {}, ii:{}".format(req_len, ii) print "pmany_typos[ii]:{}".format(many_typos[ii]) return many_typos
def __call__(self, value): res = zxcvbn.password_strength(value) if res.get('entropy') < self.password_minimum_entropy: raise ValidationError(self.message % _("Password is too weak"), code=self.code)
def __call__(self,value): res = zxcvbn.password_strength(value) if res.get('entropy') < PASSWORD_MIN_ENTROPY: raise ValidationError( self.message % _("Password is too weak"), code=self.code)
def entropy(w): try: return password_strength(w)['entropy'] except Exception as e: print(e) return -1
__author__ = 'kyhwana' import zxcvbn import sys passwordfile = open(sys.argv[1], 'r') entropyscore = sys.argv[2] for line in passwordfile: result = zxcvbn.password_strength(line.rstrip("\n")) if result["entropy"] > float(entropyscore): print("Password: "******"password"] + " Score:" + repr(result["score"]) + " Entropy:" + repr(result["entropy"]) )
def entropy(str): return password_strength(str)
def safe_secret_assignment(context): is_assignment = False is_target_likely_secret = False is_safe_secret_source = False is_hardcoded_string = False discounted_entropy_string = False entropy = 0 entropy_per_char = 0 if not context.string_val: return statement = context.statement["node"] if isinstance(statement, ast.Assign): is_assignment = True is_target_likely_secret = is_assignment_target_secret(context) if is_target_likely_secret: if isinstance(statement.value, ast.Call): f = statement.value.func func_name_parts = [] while True: if isinstance(f, ast.Attribute): func_name_parts.insert(0, f.attr) f = f.value elif isinstance(f, ast.Name): func_name_parts.insert(0, f.id) source_name = ".".join(func_name_parts) if source_name in SAFE_SECRET_SOURCES: is_safe_secret_source = True break elif isinstance(f, ast.Str): is_hardcoded_string = True logging.warning("!!STRING!! %s" % str(func_name_parts)) string = context.string_val discounted_entropy_string = any( (pattern.search(string) for pattern in ENTROPY_PATTERNS_TO_DISCOUNT) ) entropy = zxcvbn.password_strength(string)["entropy"] entropy_per_char = entropy / float(len(string)) break else: logging.warning("Don't know what to do with type {}".format(type(f.value))) break elif isinstance(statement.value, ast.Str): string = statement.value.s discounted_entropy_string = any((pattern.search(string) for pattern in ENTROPY_PATTERNS_TO_DISCOUNT)) entropy = zxcvbn.password_strength(string)["entropy"] entropy_per_char = entropy / float(len(string)) is_hardcoded_string = True else: # not assignment -- let's just look at the string itself string = context.string_val discounted_entropy_string = any((pattern.search(string) for pattern in ENTROPY_PATTERNS_TO_DISCOUNT)) entropy = zxcvbn.password_strength(string)["entropy"] entropy_per_char = entropy / float(len(string)) # scoring confidence = 0 if is_assignment: if is_target_likely_secret: if not is_hardcoded_string and not is_safe_secret_source: return bandit.Issue( severity=bandit.MEDIUM, confidence=bandit.LOW, text="Unknown secret source assigned to '(%s)'" % assignment_target_pretty(context), ) elif is_hardcoded_string and not discounted_entropy_string: confidence += 2 if (entropy > 80 or (entropy > 40 and entropy_per_char > 3)) and not discounted_entropy_string: confidence += 1 if entropy >= 120 and not discounted_entropy_string: confidence += 1 debug = { "discounted_entropy_string": discounted_entropy_string, "entropy": entropy, "entropy_per_char": entropy_per_char, "is_target_likely_secret": is_target_likely_secret, "is_assignment": is_assignment, "is_hardcoded_string": is_hardcoded_string, "is_safe_secret_source": is_safe_secret_source, } # print(debug) if confidence >= 1: if confidence == 1: confidence = bandit.LOW elif confidence == 2: confidence = bandit.MEDIUM else: confidence = bandit.HIGH if is_assignment: return bandit.Issue( severity=confidence, confidence=confidence, text="Possible hardcoded secret assigned to '%s'" % assignment_target_pretty(context), ) else: return bandit.Issue( severity=confidence, confidence=confidence, text="Possible hardcoded secret '%s...%s'" % (string[:4], string[-4:]), )
def initiate(): #file_path = MAIN_DIR + 'rockyou-withcount.txt' # file_path = MAIN_DIR + 'rockyou-ascii.txt' # for quick checks file_path = MAIN_DIR + 'rockyou-ascii_3.txt' ## #with codecs.open(file_path,encoding ='utf-8',mode='rb') as ff: # TODO REMOVE with open(file_path, 'rb') as ff: # at the end of the file the format is broken. simply deleted it manually START = time() print("start:{}".format(START)) pw_d = {} typo_d = {} #for line in all_data: # sum_all_users = 0 for line in ff: try: tup = (line.split()) count = int(tup[0]) splitted_str = [x for x in tup[1:]] pw = ' '.join(splitted_str) sum_all_users += count if pw in pw_d: cc = pw_d[pw] pw_d[pw] = count + cc else: pw_d[pw] = count except UnicodeError as e: # shouldn't happen because the file manipulation is done before print "line: {}".format(line) raise e except ValueError as e: # password contains space so split fails print "line: {}".format(line) raise e except KeyError as e: print("KeyError") raise e # out of 'for', out of file # for now - pw_d format is- pw_d[pw] = count for pw, pw_count in pw_d.iteritems(): # on online attack - ALL weak psswords will be part of the possibilities (even if they're weak) #if ONLINE_ATTACK: pw_pp = float(pw_count) / sum_all_users # adding the pw as a possile "typo" - possible attack input try: typo_sum_pp, pws_with_this_typo = typo_d[pw] pws_with_this_typo.append((pw, 1)) typo_d[pw] = (typo_sum_pp + 1, pws_with_this_typo) except KeyError: # first time typo_d[pw] = (1, [(pw, 1)]) pw_ent_bits = password_strength(pw)['entropy'] # too_weak = pw_ent_bits < MIN_ENT typos = get_pos_typos(pw, pw_ent_bits, 1, NNN) # a weak password might have a strong typo # therefore we're not skipping #if too_weak: # doesn't enter hashCache # continue pw_d[pw] = (pw_pp, typos) for tt, tt_pp in typos: actual_tt_pp = tt_pp * pw_pp try: # sum_p_of_typo, pws_with_this_typo = typo_d[tt] pws_with_this_typo.append((pw, actual_tt_pp)) typo_d[tt] = (sum_p_of_typo + actual_tt_pp, pws_with_this_typo) except KeyError: # first time typo_d[tt] = (actual_tt_pp, [(pw, actual_tt_pp)]) print("empty in dic:{}".format('' in pw_d)) # TODO REMOVE print("Finished building the pw dict. len:{}".format(len(pw_d))) print("Finished building the typo dict. len:{}".format(len(typo_d))) print("Building marisa-trie") GLOBAL_TRIE = marisa_trie.Trie( [word in itertools.chain(pw_d.keys(), typo_d.keys())]) pw_save_path = MAIN_DIR + 'pw_left.txt' typo_save_path = MAIN_DIR + 'typos_left.txt' print("Starting to build typo dict") # WE HAVE DUPLICATE PW from normalizing MAX_PW_PER_TYPO = 0 with open(pw_save_path, 'wb') as write_pw: with open(typo_save_path, 'wb') as write_typo: print "converting to marisa-based-ids" pw_id_d = {} typo_id_d = {} # if ONLINE ATTACK then pws are in the typo_trie # better for continuity print "Creating id dicts, and writing to files" UTF8 = 'utf-8' for pw, (pw_pp, typo_and_p_list) in pw_d.iteritems(): # print "pw:{}, count:{}, typ_lis:{}".format(pw,count,typ_lis) # TODO REMOVE pw_id = GLOBAL_TRIE.key_id(pw.decode(UTF8)) typos_id_list = [(GLOBAL_TRIE.key_id((tt).decode(UTF8)), pp) for (tt, pp) in typ_lis] pw_id_d[pw_id] = (pw_pp, typos_id_list) # line = ' '.join([ str(pw_id), str(pw_pp), ' '.join([ str(tt) + ' ' + str(pp) for (tt, pp) in typos_id_list ]), '\n' ]) write_pw.write(line) for typo, (sum_typo_pp, pw_lis) in typo_d.iteritems(): # pw_list is [(pw1,p1),(pw2,p22),...] MAX_PW_PER_TYPO = max(MAX_PW_PER_TYPO, len(pw_lis)) typo_id = GLOBAL_TRIE.key_id(typo.decode(UTF8)) #try: pw_id_lis = [(GLOBAL_TRIE.key_id(pw.decode(UTF8)), pp) for (pw, pp) in pw_lis] # turn to int? # except ValueError as e: # TODO REMOVE # print pw_lis # raise e typo_id_d[typo_id] = (sum_typo_pp, pw_id_lis) # turn to int ? # #line = str(typo_id) + ' ' +str(count) + ' ' + ' '.join([str(pw) for pw in pw_id_lis]) line = ' '.join([ str(typo_id), str(sum_typo_pp), ' '.join([ str(pw) + ' ' + str(pw_pp) for (pw, pw_pp) in pw_id_lis ]), '\n' ]) write_typo.write(line) print "finished converting!" print "MAX : {}".format(MAX_PW_PER_TYPO) print " saving marisa trie :)" marisa_path = MAIN_DIR + "marisa_all.txt" with open(marisa_path, 'wb') as ff: for word, code in GLOBAL_TRIE.items(): ff.write(' '.join(str(code), str(word))) print "finished writing marisa_trie" my_count = 0 for typo in typo_d: print("t:{},c:{}".format(typo, typo_d[typo])) my_count += 1 if my_count >= 5: break my_count = 0 for pw, (typ_lis) in pw_d.iteritems(): print("pw: {}, count:{}, typos: {}".format(pw, count, typ_lis)) my_count += 1 if my_count >= 5: break END = time() print("ended: {}".format(END)) return pw_id_d, typo_id_d, GLOBAL_TRIE
__author__ = 'kyhwana' import zxcvbn import sys passwordfile = open(sys.argv[1], 'r') entropyscore = sys.argv[2] for line in passwordfile: result = zxcvbn.password_strength(line.rstrip("\n")) if result["entropy"] > float(entropyscore): print("Password: "******"password"] + " Score:" + repr(result["score"]) + " Entropy:" + repr(result["entropy"]))
def __call__(self, value): res = zxcvbn.password_strength(value) if res.get('entropy') < PASSWORD_MIN_ENTROPY: raise ValidationError(PASSWORD_MIN_ENTROPY_MESSAGE, code=self.code)
def update_password_meta(self, raw_password): pws = password_strength(raw_password) self.password_entropy = pws['entropy'] self.password_score = pws['score'] self.save()
def post(self, **post): try: data = Bunch(post) except Exception as e: if config.get('debug', False): raise return 'json:', dict(success=False, message=_("Unable to parse data."), data=post, exc=str(e)) query = dict(active=True) query[b'username'] = data.id query_user = User.objects(**query).first() if query_user.id != user.id: raise HTTPForbidden if data.form == "changepassword": passwd_ok, error_msg = _check_password(data.passwd, data.passwd1) if not passwd_ok: return 'json:', dict(success=False, message=error_msg, data=data) if isinstance(data.old, unicode): data.old = data.old.encode('utf-8') if not User.password.check(user.password, data.old): return 'json:', dict(success=False, message=_("Old password incorrect."), data=data) #If the password isn't strong enough, reject it if(zxcvbn.password_strength(data.passwd).get("score") < MINIMUM_PASSWORD_STRENGTH): return 'json:', dict(success=False, message=_("Password provided is too weak. please add more characters, or include lowercase, uppercase, and special characters."), data=data) user.password = data.passwd user.save() elif data.form == "addotp": if isinstance(data.password, unicode): data.password = data.password.encode('utf-8') identifier = data.otp client = yubico.Yubico( config['yubico.client'], config['yubico.key'], boolean(config.get('yubico.secure', False)) ) if not User.password.check(user.password, data.password): return 'json:', dict(success=False, message=_("Password incorrect."), data=data) try: status = client.verify(identifier, return_response=True) except: return 'json:', dict(success=False, message=_("Failed to contact YubiCloud."), data=data) if not status: return 'json:', dict(success=False, message=_("Failed to verify key."), data=data) if not User.addOTP(user, identifier[:12]): return 'json:', dict(success=False, message=_("YubiKey already exists."), data=data) elif data.form == "removeotp": identifier = data.otp if not User.removeOTP(user, identifier[:12]): return 'json:', dict(success=False, message=_("YubiKey invalid."), data=data) elif data.form == "configureotp": if isinstance(data.password, unicode): data.password = data.password.encode('utf-8') rotp = True if 'rotp' in data else False if not User.password.check(user.password, data.password): return 'json:', dict(success=False, message=_("Password incorrect."), data=data) user.rotp = rotp user.save() #Handle the user attempting to delete their account elif data.form == "deleteaccount": if isinstance(data.passwd, unicode): data.passwd = data.passwd.encode('utf-8') #Make the user enter their username so they know what they're doing. if not user.username == data.username.lower(): return 'json:', dict(success=False, message=_("Username incorrect."), data=data) #Check whether the user's supplied password is correct if not User.password.check(user.password, data.passwd): return 'json:', dict(success=False, message=_("Password incorrect."), data=data) #Make them type "delete" exactly if not data.confirm == "delete": return 'json:', dict(success=False, message=_("Delete was either misspelled or not lowercase."), data=data) #Delete the user account and then deauthenticate the browser session log.info("User %s authorized the deletion of their account.", user) user.delete() deauthenticate() #Redirect user to the root of the server instead of the settings page return 'json:', dict(success=True, location="/") #Handle the user attempting to change the email address associated with their account elif data.form == "changeemail": if isinstance(data.passwd, unicode): data.passwd = data.passwd.encode('utf-8') #Check whether the user's supplied password is correct if not User.password.check(user.password, data.passwd): return 'json:', dict(success=False, message=_("Password incorrect."), data=data) #Check that the two provided email addresses match if not data.newEmail.lower() == data.newEmailConfirm.lower(): return 'json:', dict(success=False, message=_("Provided email addresses do not match."), data=data) #Make sure that the provided email address is a valid form for an email address v = EmailValidator() email = data.newEmail email, err = v.validate(email) if err: return 'json:', dict(success=False, message=_("Invalid email address provided."), data=data) #Make sure that the new email address is not already taken count = User.objects.filter(**{"email": data.newEmail.lower()}).count() if not count == 0: return 'json:', dict(success=False, message=_("The email address provided is already taken."), data=data) #Change the email address in the database and catch any email validation exceptions that mongo throws user.email = data.newEmail.lower() try: user.save() except ValidationError: return 'json:', dict(success=False, message=_("Invalid email address provided."), data=data) except NotUniqueError: return 'json:', dict(success=False, message=_("The email address provided is already taken."), data=data) #Handle the user attempting to merge 2 accounts together elif data.form == "mergeaccount": if isinstance(data.passwd, unicode): data.passwd = data.passwd.encode('utf-8') if isinstance(data.passwd2, unicode): data.passwd2 = data.passwd2.encode('utf-8') #Make the user enter their username so they know what they're doing. if user.username != data.username.lower() and user.username != data.username: return 'json:', dict(success=False, message=_("First username incorrect."), data=data) #Check whether the user's supplied password is correct if not User.password.check(user.password, data.passwd): return 'json:', dict(success=False, message=_("First password incorrect."), data=data) #Make sure the user isn't trying to merge their account into itself. if data.username.lower() == data.username2.lower(): return 'json:', dict(success=False, message=_("You can't merge an account into itself."), data=data) #Make the user enter the second username so we can get the User object they want merged in. if not User.objects(username=data.username2.lower()) and not User.objects(username=data.username2): return 'json:', dict(success=False, message=_("Unable to find user by second username."), data=data) other = User.objects(username=data.username2).first() if not other: other = User.objects(username=data.username2.lower()).first() #Check whether the user's supplied password is correct if not User.password.check(other.password, data.passwd2): return 'json:', dict(success=False, message=_("Second password incorrect."), data=data) #Make them type "merge" exactly if data.confirm != "merge": return 'json:', dict(success=False, message=_("Merge was either misspelled or not lowercase."), data=data) log.info("User %s merged account %s into %s.", user.username, other.username, user.username) user.merge(other) #Redirect user to the root of the server instead of the settings page return 'json:', dict(success=True, location="/") else: return 'json:', dict(success=False, message=_("Form does not exist."), location="/") return 'json:', dict(success=True, location="/account/settings")
def post(self, **post): try: data = Bunch(post) except Exception as e: if config.get('debug', False): raise return 'json:', dict(success=False, message=_("Unable to parse data."), data=post, exc=str(e)) query = dict(active=True) query[b'username'] = data.id user = User.objects(**query).first() if data.form == "changepassword": passwd_ok, error_msg = _check_password(data.passwd, data.passwd1) if not passwd_ok: return 'json:', dict(success=False, message=error_msg, data=data) if isinstance(data.old, unicode): data.old = data.old.encode('utf-8') if not User.password.check(user.password, data.old): return 'json:', dict(success=False, message=_("Old password incorrect."), data=data) #If the password isn't strong enough, reject it if (zxcvbn.password_strength(data.passwd).get("score") < MINIMUM_PASSWORD_STRENGTH): return 'json:', dict( success=False, message= _("Password provided is too weak. please add more characters, or include lowercase, uppercase, and special characters." ), data=data) user.password = data.passwd user.save() elif data.form == "addotp": if isinstance(data.password, unicode): data.password = data.password.encode('utf-8') identifier = data.otp client = yubico.Yubico(config['yubico.client'], config['yubico.key'], boolean(config.get('yubico.secure', False))) if not User.password.check(user.password, data.password): return 'json:', dict(success=False, message=_("Password incorrect."), data=data) try: status = client.verify(identifier, return_response=True) except: return 'json:', dict(success=False, message=_("Failed to contact YubiCloud."), data=data) if not status: return 'json:', dict(success=False, message=_("Failed to verify key."), data=data) if not User.addOTP(user, identifier[:12]): return 'json:', dict(success=False, message=_("YubiKey already exists."), data=data) elif data.form == "removeotp": identifier = data.otp if not User.removeOTP(user, identifier[:12]): return 'json:', dict(success=False, message=_("YubiKey invalid."), data=data) elif data.form == "configureotp": if isinstance(data.password, unicode): data.password = data.password.encode('utf-8') rotp = True if 'rotp' in data else False if not User.password.check(user.password, data.password): return 'json:', dict(success=False, message=_("Password incorrect."), data=data) user.rotp = rotp user.save() #Handle the user attempting to delete their account elif data.form == "deleteaccount": if isinstance(data.passwd, unicode): data.passwd = data.passwd.encode('utf-8') #Make the user enter their username so they know what they're doing. if not user.username == data.username.lower(): return 'json:', dict(success=False, message=_("Username incorrect."), data=data) #Check whether the user's supplied password is correct if not User.password.check(user.password, data.passwd): return 'json:', dict(success=False, message=_("Password incorrect."), data=data) #Make them type "delete" exactly if not data.confirm == "delete": return 'json:', dict( success=False, message=_( "Delete was either misspelled or not lowercase."), data=data) #Delete the user account and then deauthenticate the browser session log.info("User %s authorized the deletion of their account.", user) user.delete() deauthenticate() #Redirect user to the root of the server instead of the settings page return 'json:', dict(success=True, location="/") #Handle the user attempting to change the email address associated with their account elif data.form == "changeemail": if isinstance(data.passwd, unicode): data.passwd = data.passwd.encode('utf-8') #Check whether the user's supplied password is correct if not User.password.check(user.password, data.passwd): return 'json:', dict(success=False, message=_("Password incorrect."), data=data) #Check that the two provided email addresses match if not data.newEmail.lower() == data.newEmailConfirm.lower(): return 'json:', dict( success=False, message=_("Provided email addresses do not match."), data=data) #Make sure that the provided email address is a valid form for an email address v = EmailValidator() email = data.newEmail email, err = v.validate(email) if err: return 'json:', dict( success=False, message=_("Invalid email address provided."), data=data) #Make sure that the new email address is not already taken count = User.objects.filter(**{ "email": data.newEmail.lower() }).count() if not count == 0: return 'json:', dict( success=False, message=_("The email address provided is already taken."), data=data) #Change the email address in the database and catch any email validation exceptions that mongo throws user.email = data.newEmail.lower() try: user.save() except ValidationError: return 'json:', dict( success=False, message=_("Invalid email address provided."), data=data) except NotUniqueError: return 'json:', dict( success=False, message=_("The email address provided is already taken."), data=data) #Handle the user attempting to merge 2 accounts together elif data.form == "mergeaccount": if isinstance(data.passwd, unicode): data.passwd = data.passwd.encode('utf-8') if isinstance(data.passwd2, unicode): data.passwd2 = data.passwd2.encode('utf-8') #Make the user enter their username so they know what they're doing. if user.username != data.username.lower( ) and user.username != data.username: return 'json:', dict(success=False, message=_("First username incorrect."), data=data) #Check whether the user's supplied password is correct if not User.password.check(user.password, data.passwd): return 'json:', dict(success=False, message=_("First password incorrect."), data=data) #Make sure the user isn't trying to merge their account into itself. if data.username.lower() == data.username2.lower(): return 'json:', dict( success=False, message=_("You can't merge an account into itself."), data=data) #Make the user enter the second username so we can get the User object they want merged in. if not User.objects( username=data.username2.lower()) and not User.objects( username=data.username2): return 'json:', dict( success=False, message=_("Unable to find user by second username."), data=data) other = User.objects(username=data.username2).first() if not other: other = User.objects(username=data.username2.lower()).first() #Check whether the user's supplied password is correct if not User.password.check(other.password, data.passwd2): return 'json:', dict(success=False, message=_("Second password incorrect."), data=data) #Make them type "merge" exactly if data.confirm != "merge": return 'json:', dict( success=False, message=_("Merge was either misspelled or not lowercase."), data=data) log.info("User %s merged account %s into %s.", user.username, other.username, user.username) user.merge(other) #Redirect user to the root of the server instead of the settings page return 'json:', dict(success=True, location="/") else: return 'json:', dict(success=False, message=_("Form does not exist."), location="/") return 'json:', dict(success=True, location="/account/settings")
def good_enough_password(form, field): if password_strength(field.data)['score'] < 4: msg = 'Get a better password' raise ValidationError(msg)
def run(db, args): total, local_users, domain_users, computers = db.counts print("cracke-dit report for {}\n".format(args.domain)) print("Local / Domain users:\t{}/{}".format(local_users, domain_users)) if not args.only_enabled: print("Enabled / disabled users:\t{}/{}".format(*db.user_counts)) if not args.only_users: print("Computer accounts:\t{}\t{:.2f}%".format( computers, (computers / total) * 100)) cracked, blank, historic = db.password_stats print("Passwords cracked:\t{}/{}\t{:.2f}%".format(cracked, total, (cracked / total) * 100)) print("Historic passwords:\t{}\t{:.2f}%".format(historic, (historic / total) * 100)) only_alpha, with_special = db.password_char_stats print("Only alphanumeric:\t{}\t{:.2f}%".format(only_alpha, (only_alpha / total) * 100)) print("With 'special char':\t{}\t{:.2f}%".format( with_special, (with_special / total) * 100)) headers = ["Password", "Length", "Count", "Score", "Users"] fmt_lambda = lambda password, count, score, users: [ password, len(password), count, __coloured_score(score), __process_users(users) ] take_top = 10 top_passwords = db.get_top_passwords( sortby=lambda (password, count, score, users): count, reverse=True, limit=take_top) __print_table(title="Top {} Passwords (by use)".format(take_top), headers=headers, align=[">", "<", "<", "<", ""], values=top_passwords, format=fmt_lambda) take_top = 5 bad_pass = db.get_top_passwords( sortby=lambda (password, count, score, users): (zxcvbn.password_strength(password)["score"], len(password)), reverse=False, limit=take_top) __print_table(title="Top {} Worst Passwords".format(take_top), headers=headers, align=[">", "<", "<", "<", ""], values=bad_pass, format=fmt_lambda) __graph_passwords_containing( "Months", db, OrderedDict([(calendar.month_name[m], 0) for m in range(1, 13)])) __graph_passwords_containing( "Days", db, OrderedDict([(calendar.day_name[d], 0) for d in range(0, 7)]))
def initiate_with_a_trie_file(): # so we should only have a list of names + typos file_path = MAIN_DIR + 'rockyou-ascii.txt' # for quick checks # file_path = MAIN_DIR + 'rockyou-ascii_3.txt' ## print "Starting to create the trie" # list_for_marisa = [] # with open(TRIE_PATH,'rb') as trie_file: # for line in trie_file: # tup = line.split() # code = ' '.join(tup[1:]) # # print "code:{}, code length:{}".format(code,len(code)) # TODO REMOVE # list_for_marisa.append(code) # TRIE_ALL = marisa_trie.Trie(list_for_marisa) # TODO CHANGE TO READ FROM FILE another_trie_path = MAIN_DIR + 'myTrieYay.txt' TRIE_ALL = marisa_trie.Trie() TRIE_ALL.load(another_trie_path) print "loaded the marisa_trie" # print "Trie created with length: {}".format(len(list_for_marisa)) # # NUM_OF_LINES = 10**8 # TODO CHANGE # TRIE SIZE NUM_OF_LINES = 265796 MAX_LENGTH = (15 * 2) + 1 UTF8 = 'utf-8' # .dcode(UTF8) UNINIT = -1.0 DEF_LINE = [UNINIT] * MAX_LENGTH pw_arr = np.array([DEF_LINE] * NUM_OF_LINES) typo_arr = np.array([DEF_LINE] * NUM_OF_LINES) SUM_ALL = 1000 # TODO CHANGE according to check print "Starting to read from file and collect the data" with open(file_path, 'rb') as ff: # at the end of the file the format is broken. simply deleted it manually START = time() print("start:{}".format(START)) #for line in all_data: # count_fails = 0 for line in ff: #try: tup = (line.split()) count = int(tup[0]) pw_pp = float(count) / SUM_ALL splitted_str = [x for x in tup[1:]] pw = ' '.join(splitted_str) pw_ent_bits = password_strength(pw)['entropy'] pw_id = TRIE_ALL.key_id(pw.decode(UTF8)) typos = get_pos_typos(pw, pw_ent_bits, 1, NNN) typos_with_id = [(TRIE_ALL.key_id(tt.decode(UTF8)), pp) for (tt, pp) in typos] # writing for pw pw_arr[pw_id][0] = pw_pp index_in_pw_arr = 1 for tt_id, pp in typos_with_id: try: # updating pw_array pw_arr[pw_id][index_in_pw_arr] = tt_id pw_arr[pw_id][ index_in_pw_arr + 1] = pp ## this is the probability of having this typo in cache from that pw index_in_pw_arr += 2 # updating typo_arr rel_typo_pp = pp * pw_pp # the typo gain probabily based in the pw's prob as well old_typo_pp = typo_arr[tt_id][0] if old_typo_pp == UNINIT: # AKA un initiated typo_arr[tt_id][0] = rel_typo_pp else: typo_arr[tt_id][0] += rel_typo_pp index_in_typo_arr = 1 # will raise error if out of length while index_in_typo_arr != UNINIT: # skipping filled index_in_typo_arr += 2 # typo_arr[tt_id][index_in_typo_arr] = pw_id typo_arr[tt_id][index_in_typo_arr + 1] = pp except IndexError as e: print "reached indexError: pw_I={}, typo_I:{}".format( index_in_pw_arr, index_in_typo_arr) # adding for thse typos # except Exception as e: # count_fails += 1 # print "failed on something. count={}".format(count_fails) # raise e print "Finished aggregating the data" print "Starting to calculate attacks" # out of open file, still in def # calculating the ATTACK QUERIES = 1000 while QUERIES: # find max max_score = 0 max_typo_id = 0 for typo_id in xrange(NUM_OF_LINES): t_p_sum = typo_arr[typo_id][0] max_typo_id = typo_id if (t_p_sum != UNINIT and t_p_sum > max_score) else max_typo_id # found max added_p = typo_arr[max_typo_id][0] print "\n" * 2, "*" * 20 # TODO REMOVE print "chose {},({}) with {} users".format( max_typo_id, TRIE_ALL.restore_key(max_typo_id), added_p) broken += added_p # removing chosen typo_arr[max_typo_id][ 0] = 0 # TODO CHANGE? the easiest way to remove it # need to also remove from other pw's for index_in_typo_line in xrange( 1, MAX_LENGTH, 2): # 2 adjasant indexes are used each time # if reached the end of initiated cells: if typo_arr[typo_id][index_in_typo_line] == UNINIT: break pw_id = typo_arr[typo_id][index_in_typo_line] pp_of_chosen_typo_for_pw = typo_arr[typo_id][index_in_typo_line + 1] print "pw_id:{}, count: {}".format(pw_id, count) # TODO REMOVE try: # calc new prob of pw # update the prob of all the other typos of that pw # gaining the prob of chosen typo accuring for that pw old_pw_pp = pw_arr[pw_id][0] new_pw_pp = old_pw_pp * (1 - pp_of_chosen_typo_for_pw) pw_arr[pw_id][0] = new_pw_pp # updating in case it's a typo as well # TODO CHECK _ I think we entered all pws into typo_arr typo_arr[pw_id][0] -= (old_pw_pp - new_pw_pp) sum_of_rest_typos_pp = 0 for index_in_pw_arr in xrange(1, MAX_LENGTH, 2): if index_in_pw_arr == UNINIT: break sum_of_rest_typos_pp += pw_arr[pw_id][index_in_pw_arr + 1] assert sum_of_rest_typos_pp and sum_of_rest_typos_pp < 1 # TODO CHANGE - should be zero otherwise we wouldn't have reached that typo # re-normalizing the pp of the pw's typos for index_in_pw_arr in xrange(1, MAX_LENGTH, 2): if index_in_pw_arr == UNINIT: break tt_id = pw_arr[pw_id][index_in_pw_arr] old_tt_pp = pw_arr[pw_id][index_in_pw_arr + 1] new_tt_pp = old_tt_pp / sum_of_rest_typos_pp pw_arr[pw_id][index_in_pw_arr + 1] = new_tt_pp # finding the pw's index in the typo's row (in typo_arr) pw_index_in_typo_arr = 1 while typo_arr[tt_id][pw_index_in_typo_arr] != pw_id: pw_index_in_typo_arr += 2 # should be found - so not checking bounds typo_arr[tt_id][0] -= (old_tt_pp - new_tt_pp) typo_arr[tt_id][pw_index_in_typo_arr + 1] = new_tt_pp except TypeError as e: # TODO REMOVE print "bummer" raise e QUERIES -= 1 print "BROKEN %: {}".format(broken)
def __call__(self, value): res = zxcvbn.password_strength(value) if res.get('entropy') < PASSWORD_MIN_ENTROPY: raise ValidationError(self.message % _("Password is too weak"), code=self.code)