Доброго времени суток
Не очень давно я написал гуёвый аналог Google Authenticator для Ubuntu\Debian на питоне и вселилась мне в голову мысль немного изменит алгоритм генерации пин-кода, для того, чтобы генерировать пароли. Долго идея зрела у меня в голове, пока не произошёл взлом LastPass. Так вот... Практически все менеджеры паролей работают по схеме "куча паролей для сервисов шифруются одним мастер-паролем" и всё это хранится на удалённом сервере. И голову западает идея - "а зачем хранить и шифровать пароли, когда можно тупо его генерировать". Собственно так и родилась идея. Исходник прилагаю
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import hmac
import sha
import base64
import struct
import hashlib
import re
def calculate(key_length, key_hash_one, key_hash_two, password_length):
hashes = []
for i in xrange(32):
msg = '%s%s%s' % (ord(key_hash_two[i]), ord(key_hash_two[i+32]), key_length*password_length)
hash = hmac.new(key_hash_one, msg, hashlib.sha512).digest()
offset_one = ord(key_hash_two[i]) & 0xf
offset_two = ord(key_hash_two[i+32]) & 0xf
binary_one = struct.unpack('>Q', hash[offset_one:offset_one+8])[0]
binary_two = struct.unpack('>Q', hash[offset_two:offset_two+8])[0]
password = re.sub('=', '', base64.b64encode(str(binary_one*binary_two)))
hashes.append(password[-(password_length):])
return hashes
if __name__ == '__main__':
key = 'master key'
key_length = len(key)
key_hash_one = hashlib.sha512(key).digest()
key_hash_two = hashlib.sha512(key[::-1]).digest()
passwords = []
for password_length in range(10, 13):
passwords = passwords + calculate(key_length, key_hash_one, key_hash_two, password_length)
passwords = passwords + calculate(key_length, key_hash_two, key_hash_one, password_length)
for i,j in enumerate(passwords):
print i, j
Кратко механизм генерации:
Юзер вводит мастер-пароль
От мастер-пароля высчитывается длина, sha-512 (1) и sha-512 (2) от его зеркального отражения
Затем в цикле из 32 шагов от (2) берутся i-ый и i+32 байты в виде ascii-кодов и к ним добавляется произведение длины ключа и длины паролей на выходе - в результате мы получаем сообщение
С помошью HMAC-SHA512 мы получаем бинарную строку, используя (1) как ключ для подписывания сообщения
Из полученной бинарной строки мы берём i-ый и i+32 байты в виде ascii-кодов в 16-тиричном формате
Используя полученные байты как номера оффсетов мы берём от бинарной строки две подстроки, начинающиеся этими оффсетами
Полученные подстроки перемножаем друг с другом и кодируем в base64
От полученной строки с конца берём нужное количество символов, предварительно вырезая знак "="
В результате мы получаем огромное количество паролей, которые не нужно запоминать - нужно помнить один единственный мастер-пароль. Также не нужно нигде хранить генерируемые пароли - необходимо лишь будет хранить список в виде "пароль под номером * назначен сервису "MotoFan.ru"" и т.д.
При всё при этом компрометация одного пароля из списка не приведёт к получению секретного ключа, при условии что изначально мастер-пароль не "password" и не "qwerty"
Собственно был бы признателен, если бы кто-нибудь взялся реализовать сею штуку для Android с интерфейсом как у Google Authenticator
Сообщение отредактировал DDA-E398 - 2.7.2015, 12:46
Не очень давно я написал гуёвый аналог Google Authenticator для Ubuntu\Debian на питоне и вселилась мне в голову мысль немного изменит алгоритм генерации пин-кода, для того, чтобы генерировать пароли. Долго идея зрела у меня в голове, пока не произошёл взлом LastPass. Так вот... Практически все менеджеры паролей работают по схеме "куча паролей для сервисов шифруются одним мастер-паролем" и всё это хранится на удалённом сервере. И голову западает идея - "а зачем хранить и шифровать пароли, когда можно тупо его генерировать". Собственно так и родилась идея. Исходник прилагаю
Код
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import hmac
import sha
import base64
import struct
import hashlib
import re
def calculate(key_length, key_hash_one, key_hash_two, password_length):
hashes = []
for i in xrange(32):
msg = '%s%s%s' % (ord(key_hash_two[i]), ord(key_hash_two[i+32]), key_length*password_length)
hash = hmac.new(key_hash_one, msg, hashlib.sha512).digest()
offset_one = ord(key_hash_two[i]) & 0xf
offset_two = ord(key_hash_two[i+32]) & 0xf
binary_one = struct.unpack('>Q', hash[offset_one:offset_one+8])[0]
binary_two = struct.unpack('>Q', hash[offset_two:offset_two+8])[0]
password = re.sub('=', '', base64.b64encode(str(binary_one*binary_two)))
hashes.append(password[-(password_length):])
return hashes
if __name__ == '__main__':
key = 'master key'
key_length = len(key)
key_hash_one = hashlib.sha512(key).digest()
key_hash_two = hashlib.sha512(key[::-1]).digest()
passwords = []
for password_length in range(10, 13):
passwords = passwords + calculate(key_length, key_hash_one, key_hash_two, password_length)
passwords = passwords + calculate(key_length, key_hash_two, key_hash_one, password_length)
for i,j in enumerate(passwords):
print i, j
Кратко механизм генерации:
Юзер вводит мастер-пароль
От мастер-пароля высчитывается длина, sha-512 (1) и sha-512 (2) от его зеркального отражения
Затем в цикле из 32 шагов от (2) берутся i-ый и i+32 байты в виде ascii-кодов и к ним добавляется произведение длины ключа и длины паролей на выходе - в результате мы получаем сообщение
С помошью HMAC-SHA512 мы получаем бинарную строку, используя (1) как ключ для подписывания сообщения
Из полученной бинарной строки мы берём i-ый и i+32 байты в виде ascii-кодов в 16-тиричном формате
Используя полученные байты как номера оффсетов мы берём от бинарной строки две подстроки, начинающиеся этими оффсетами
Полученные подстроки перемножаем друг с другом и кодируем в base64
От полученной строки с конца берём нужное количество символов, предварительно вырезая знак "="
В результате мы получаем огромное количество паролей, которые не нужно запоминать - нужно помнить один единственный мастер-пароль. Также не нужно нигде хранить генерируемые пароли - необходимо лишь будет хранить список в виде "пароль под номером * назначен сервису "MotoFan.ru"" и т.д.
При всё при этом компрометация одного пароля из списка не приведёт к получению секретного ключа, при условии что изначально мастер-пароль не "password" и не "qwerty"
Собственно был бы признателен, если бы кто-нибудь взялся реализовать сею штуку для Android с интерфейсом как у Google Authenticator
Сообщение отредактировал DDA-E398 - 2.7.2015, 12:46