Менеджер паролей без хранения
Всем привет!
Хочу поделиться с народом своей идеей по поводу безопасного хранения паролей. Сторонние менеджеры паролей мне всегда не нравились. Хранение сокровенного у чужого дяди – идея ну очень так себе. Можно сколько угодно клясться, что все надежно, что утечки маловероятны и т.д. Но одна утечка – и все что нажито непосильным трудом погибнет.
Поэтому, я, руководствуясь принципом «хочешь, чтобы было сделано хорошо – сделай сам», решил создать свое решение этой проблемы.
Задачи стояли следующие:
Я программист не настоящий, так что алгоритм должен быть простым в реализации.
Он должен быть кроссплатформенным: Android/Linux/Windows.
Пароли в принципе не должны храниться нигде и ни в каком виде – это и есть изюминка моей идеи.
Если кто-то получит доступ к исходным кодам – это ничего ему дать не должно. Собственно, поэтому я и решил поделиться с народом своей идеей.
Идея заключалась в следующем. Хэш чего угодно представляет собой последовательность шестнадцатеричных цифр. Эту последовательность можно разбить на блоки по две, переводим в десятичный вид, получаем остаток по модулю длины алфавита и получаем номера символов в алфавите. Для сайта нужно помнить лишь мнемонический идентификатор из хэшируемой фразы и числа для формирования алфавита.
Алгоритм заворачивается в скрипт на питоне. Интерпретаторов под Android/Linux/Windows – вагон и маленькая тележка. Далее привожу код с пояснениями.
Импортируем нужные библиотеки:
import hashlib
from textwrap import wrap
import random
Подключаем список алгоритмов хэширования. Длина хэша у них разная, сделано это для сайтов с ограничением сверху по длине пароля.
algs = ['md5', 'sha1', 'sha3_224', 'sha3_256', 'sha3_384', 'sha3_512']
Алфавит разбиваем на три куска. Отдельно цифробуквенный, отдельно знаки препинания, и отдельно пробел, решетка звездочка и обратный слэш. Третий блок почему-то кое-где запрещен в паролях, например на госуслугах.
abc_blocks = ['0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz', '!"$%&\'()+,-./:;<=>?@[]^_{|}~`', ' #*\\']
abc = ''
Принимаем на входе количество блоков. По умолчанию берем все три блока.
И задаем зерно для рандома. Это вышеупомянутое число из мнемонического идентификатора.
abc_colvo = int(input("Количество блоков (3): ") or 3)
s = int(input("Зерно для рандома: "))
Склеиваем блоки алфавита и перемешиваем его.
for i in range(abc_colvo):
abc += abc_blocks[i]
abc = list(abc)
random.seed(s)
random.shuffle(abc)
abc = ''.join(abc)
Далее вводим фразу.
memory_phrase = input('Ключевая фраза: ')
memory_phrase = bytes(memory_phrase, encoding = 'utf-8')
Запускается вычисление паролей.
print()
print('-----------------------------')
for alg in algs:
hash_key = getattr(hashlib, alg)(memory_phrase).hexdigest()
password = [hash_key[x:x+2] for x in range(0, len(hash_key), 2)]
password = list(map(lambda x: int(x, 16) % len(abc), password))
password = list(abc[x] for x in password)
password = ''.join(password)
print(alg + ':', len(password), 'chars')
print()
print(password)
print()
for block in wrap(''.join(password), 4):
print(block + ' ', end = '')
print()
print('-----------------------------')
И вуаля – вот ваши возможные пароли для сайта.
Разбивка по 4 символа нужна на тот редкий случай, если придется вводить все это с клавиатуры. Так визуально проще его читать.