Переглянути джерело

POC import password from other password managers

Try idea from #60
pull/531/head
Guillaume Vincent 4 роки тому
джерело
коміт
2bd5e49cd0
3 змінених файлів з 108 додано та 9 видалено
  1. +5
    -7
      cli/lesspass/password.py
  2. +17
    -2
      cli/tests/test_password_generation.py
  3. +86
    -0
      sandbox/test_import.py

+ 5
- 7
cli/lesspass/password.py Переглянути файл

@@ -19,7 +19,6 @@


import hashlib
import binascii

CHARACTER_SUBSETS = {
"lowercase": "abcdefghijklmnopqrstuvwxyz",
@@ -35,11 +34,10 @@ def _calc_entropy(password_profile, master_password):
+ password_profile["login"]
+ hex(password_profile["counter"])[2:]
)
return binascii.hexlify(
hashlib.pbkdf2_hmac(
"sha256", master_password.encode("utf-8"), salt.encode("utf-8"), 100000, 32
)
)
hex_entropy = hashlib.pbkdf2_hmac(
"sha256", master_password.encode("utf-8"), salt.encode("utf-8"), 100000, 32
).hex()
return int(hex_entropy, 16)


def _get_set_of_characters(rules=None):
@@ -93,7 +91,7 @@ def _render_password(entropy, password_profile):
rules = _get_configured_rules(password_profile)
set_of_characters = _get_set_of_characters(rules)
password, password_entropy = _consume_entropy(
"", int(entropy, 16), set_of_characters, password_profile["length"] - len(rules)
"", entropy, set_of_characters, password_profile["length"] - len(rules)
)
characters_to_add, character_entropy = _get_one_char_per_rule(
password_entropy, rules


+ 17
- 2
cli/tests/test_password_generation.py Переглянути файл

@@ -83,6 +83,22 @@ class TestPassword(unittest.TestCase):
generate_password(profile, master_password), "XFt0F*,r619:+}[."
)

def test_generate_password_unicode(self):
profile = {
"site": "♥ LessPass ♥",
"login": "test@example.org",
"lowercase": True,
"uppercase": True,
"digits": True,
"symbols": True,
"length": 16,
"counter": 1,
}
master_password = "password"
self.assertEqual(
generate_password(profile, master_password), "BH$>U5Lj7v9A1wB/"
)

def test_calc_entropy(self):
password_profile = {
"site": "example.org",
@@ -93,7 +109,7 @@ class TestPassword(unittest.TestCase):

self.assertEqual(
password._calc_entropy(password_profile, master_password),
b"dc33d431bce2b01182c613382483ccdb0e2f66482cbba5e9d07dab34acc7eb1e",
99600400399777174105034830393873797761817714609490038944205586760025858632478,
)

def test_get_configured_rules_empty_when_no_rules_in_profile(self):
@@ -197,4 +213,3 @@ class TestPassword(unittest.TestCase):
self.assertEqual(
password._render_password(entropy, password_profile), "gsrwvjl03d0asn"
)


+ 86
- 0
sandbox/test_import.py Переглянути файл

@@ -0,0 +1,86 @@
import unittest
from secrets import token_hex
from lesspass import password


def get_pool_of_char(password_profile):
return "abcdefghijklmnopqrstuvwxyz"


def get_rules(password_profile):
return ["lowercase"]


def get_rule_len(rule):
return 26


def generate_random_entropy():
return int(token_hex(32), 16)


def _rev_pseudo_insert_chars_to_add(entropy, old_password):
rules = get_rules(old_password)
chars_to_add = []
for rule in rules:
position = 0
chars_to_add.append((old_password[0], rule,))
old_password = old_password[1:]
entropy = (entropy + 0) * len(old_password)
return chars_to_add, old_password, entropy


def _rev_chars_to_add(chars_to_add, entropy, pool_of_char):
for char, rule in chars_to_add:
entropy = entropy * get_rule_len(rule) + pool_of_char.find(char)
return entropy


def _rev_consume_entropy(old_password, entropy, pool_of_char):
while len(old_password) != 0:
last_char = old_password[-1]
old_password = old_password[:-1]
entropy = entropy * len(pool_of_char) + pool_of_char.find(last_char)
return entropy


def reverse_entropy(old_password, password_profile):
entropy = generate_random_entropy()
e1 = entropy
rules = get_rules(old_password)
one_char_per_rule = []
for rule in rules:
position = 0
one_char_per_rule.append((old_password[0], rule,))
old_password = old_password[1:]
entropy = (entropy + 0) * len(old_password)

pool_of_char = get_pool_of_char(old_password)
for char, rule in one_char_per_rule:
entropy = entropy * get_rule_len(rule) + pool_of_char.find(char)

while old_password != "":
last_char = old_password[-1]
old_password = old_password[:-1]
entropy = entropy * len(pool_of_char) + pool_of_char.find(last_char)

return entropy


class TestImportPOC(unittest.TestCase):
def test_can_reverse_entropy(self):
password_profile = {
"site": "lesspass.com",
"login": "contact@lesspass.com",
"lowercase": True,
"uppercase": False,
"digits": False,
"symbols": False,
"length": 11,
"counter": 1,
}
master_password = "password"
entropy = password._calc_entropy(password_profile, master_password)
old_entropy = reverse_entropy("oldpassword", password_profile)
oldpassword = password._render_password(old_entropy, password_profile)
self.assertEqual(oldpassword, "oldpassword")

Завантаження…
Відмінити
Зберегти