motofan logo
Motorola Ситилинк
       
> 

Генератор паролей по мастер-паролю\ключу, на правах идеи

DDA-E398
сообщение 2.7.2015, 12:23


Ветеран
*****

Группа: Пользователи
Сообщений: 371
Регистрация: 12.3.2008
Из: Нижегородская обл.
Пользователь №: 166 356
Модель телефона: E2, A910, Е398, ATRIX2
Прошивка: разные


Настроение:
Роботаю...



Рейтинг: 327



Доброго времени суток
Не очень давно я написал гуёвый аналог 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
Юзер вышелВ друзьяВизиткаП/Я
К началу страницы
+Ответить
Zorge.R
сообщение 2.7.2015, 20:02


Ветеран
Group Icon

Группа: SysAdmin
Сообщений: 1 914
Регистрация: 4.10.2006
Из: рук в руки
Пользователь №: 101 800
Модель телефона: Note 9 Copper 512Gb
Прошивка: 1CR

Рейтинг: 2510



Могу помочь с реализацией под Android.
Юзер вышелВ друзьяВизиткаП/Я
К началу страницы
+Ответить
DDA-E398
сообщение 10.7.2015, 15:43


Ветеран
*****

Группа: Пользователи
Сообщений: 371
Регистрация: 12.3.2008
Из: Нижегородская обл.
Пользователь №: 166 356
Модель телефона: E2, A910, Е398, ATRIX2
Прошивка: разные


Настроение:
Роботаю...



Рейтинг: 327



Цитата(Zorge.R @ 2.7.2015, 23:02) *

Могу помочь с реализацией под Android.


Было бы очень здорово. Стукни в icq или jabber
Юзер вышелВ друзьяВизиткаП/Я
К началу страницы
+Ответить
DDA-E398
сообщение 18.8.2015, 15:25


Ветеран
*****

Группа: Пользователи
Сообщений: 371
Регистрация: 12.3.2008
Из: Нижегородская обл.
Пользователь №: 166 356
Модель телефона: E2, A910, Е398, ATRIX2
Прошивка: разные


Настроение:
Роботаю...



Рейтинг: 327



Код

#!/usr/bin/env python
# -*- coding: utf-8 -*-

from mom.codec.base85 import b85encode
import argparse
import getpass
import hashlib
import struct
import json
import hmac
import sha3
import sys
import re
import os


def hash_sum(hash_one, hash_two):
    hash_sum = ''
    for i in xrange(96):
        hash_sum = '%s%s%s' % (hash_sum, hash_one[i], hash_two[i])
    return hash_sum


def bin_to_str(binary):
    string = b85encode(str(binary))
    for i in xrange(len(string)):
        if i % 2 == 0:
            string = '%s%s%s' % (string[:i], string[i].upper(), string[i+1:])
        else:
            string = '%s%s%s' % (string[:i], string[i].lower(), string[i+1:])
    return string


def calc_msg(hash, i):
    offset_one = abs(ord(hash[i]) & 0xff - 72)
    offset_two = abs(ord(hash[i+96]) & 0xff - 72)
    binary_one = struct.unpack('>Q', hash[offset_one:offset_one+8])[0]
    binary_two = struct.unpack('>Q', hash[offset_two:offset_two+8])[0]
    return binary_one * binary_two


def calc_pass(key, length):
    passwords = {}
    key_length = len(key)
    ord_sum = 0
    for symbol in key:
        ord_sum = ord_sum + ord(symbol)
    hash_key_one = '%s%s' % (hashlib.sha256(key).digest(),
                             hashlib.sha512(key).digest())
    hash_key_two = '%s%s' % (hashlib.sha3_256(key).digest(),
                             hashlib.sha3_512(key).digest())
    hash_key = hash_sum(hash_key_one, hash_key_two)
    for i in xrange(96):
        msg = str(calc_msg(hash_key, i) * key_length * ord_sum * length)
        hash_hmac_one = '%s%s' % (hmac.new(hash_key, msg,
                                  hashlib.sha256).digest(),
                                  hmac.new(hash_key, msg,
                                  hashlib.sha512).digest())
        hash_hmac_two = '%s%s' % (hmac.new(hash_key[::-1], msg,
                                  hashlib.sha256).digest(),
                                  hmac.new(hash_key[::-1], msg,
                                  hashlib.sha512).digest())
        hash_hmac = hash_sum(hash_hmac_one, hash_hmac_two)
        string = bin_to_str(calc_msg(hash_hmac, i))
        passwords[i] = re.sub('[^A-Za-z0-9]+', '', string)[-length:]
    return passwords


if __name__ == '__main__':
    set_list_path = '%s/.k2pass/k2pass' % os.getenv('HOME')
    if not os.path.exists(set_list_path):
        os.mkdir('%s/.k2pass' % os.getenv('HOME'))
        with open(set_list_path, 'w') as file:
            json.dump({}, file, indent=4)
        os.chmod(set_list_path, 0600)
        set_list = {}
    else:
        with open(set_list_path, 'r') as file:
            set_list = json.load(file)

    parser = argparse.ArgumentParser()
    parser.add_argument('--set', action='store_true')
    parser.add_argument('--gen', action='store_true')
    parser.add_argument('--show', action='store_true')
    args = parser.parse_args()

    if args.gen:
        key = getpass.getpass('Key: ')
        length = int(raw_input('Length: '))
        passwords = calc_pass(key, length)
        for i in passwords.items():
            print i[0], i[1]
    if args.set:
        key = getpass.getpass('Key: ')
        length = int(raw_input('Length: '))
        passwords = calc_pass(key, length)
        for i in passwords.items():
            print i[0], i[1]
        number = raw_input('Number: ')
        service = raw_input('Service: ')
        if str(length) not in set_list:
            set_list[str(length)] = {}
        set_list[str(length)][str(number)] = service
        with open(set_list_path, 'w') as file:
            json.dump(set_list, file, indent=4)
    if args.show:
        key = getpass.getpass('Key: ')
        for length in set_list.keys():
            passwords = calc_pass(key, int(length))
            for number in set_list[length].keys():
                print '%s: %s' % (set_list[length][number],
                                  passwords[int(number)])



Вроде бы окончательный вариант. Очень много изменений в сравнении с предыдущим вариантом
Принцип генерации вкратце таков
На входе получаем мастер-ключ и длину генерируемых паролей
Высчитываем пары sha-хешей для полученного мастер ключа SHA256+SHA512 и SHA3_256+SHA3_512
Полученные пары sha-хешей склеивам друг с другом через байт (hash_key)
В цикле из 96 шагов
- Высчитываем сообщение, которое будем шифровать
Получаем два оффсета как ascii-код i-того и i+96 sha-хеша - 72 (- 72 потомучто длина нашего хеша 192 байта, а ascii-коды могут быть от 0 до 255 и оффсет должен быть как минимум в 8 октетах от конца sha-хеша)
Затем берём две подстроки длиной 8 байт в sha-хеше, начало которых определяется полученными ранее оффсетами
Перемножаем между собой полученные подстроки и умножаем их на длину мастер-пароля, на сумму ascii-кодов мастер-пароля и на длину генерируемых паролей
- Высчитываем пару hmac-хешей SHA256+SHA512, где в первом hmac-хеше в качестве ключа используем hash_key, а во втором его зеркальное отражение
Полученные пары hmac-хешей склеивам друг с другом через байт (hash_hmac)
- Высчитываем сообщение, которое в дальнейшем станет сгенерированным паролем
Получаем два оффсета как ascii-код i-того и i+96 байт hmac-хеша - 72 (- 72 потомучто длина нашего хеша 192 байта, а ascii-коды могут быть от 0 до 255 и оффсет должен быть как минимум в 8 байтах от конца hmac-хеша)
Затем берём две подстроки длиной 8 байт в hmac-хеше, начало которых определяется полученными ранее оффсетами
Перемножаем между собой полученные подстроки
Полученное произведение кодируем в base85 и в качестве большей энтропии ловеркейзим все нечётные символы и апперкейзим все чётные (string)
- Получаем пароль из string путём вырезания всех символов отличных от A-Z, a-z, 0-9 и отрезания с конца строки заданного количества символов
Юзер вышелВ друзьяВизиткаП/Я
К началу страницы
+Ответить
Генератор паролей по мастер-паролю\ключу, на правах идеи · Разработка приложений · Forum
 

Motorola Ситилинк
Ответ в темуСоздание новой темы
2 чел. читают эту тему (гостей: 2, скрытых пользователей: 0)
Пользователей: 0

 



Текстовая версия Сейчас: 22.9.2019, 17:04

Форум живёт: