python: Add initial prototype

This commit is contained in:
2021-09-22 18:28:16 +02:00
parent 7acbc7de0c
commit 93f9c75131
4 changed files with 87 additions and 0 deletions

View File

40
python/passgeny/bhash.py Normal file
View File

@ -0,0 +1,40 @@
import math
class BhashException(Exception): pass
class Bhash:
"""
Hash manipulation class.
The hash is internally treated as a big-endinan integer. This allows for
easy implementation of operations such as modulo.
Note: The consumed bits are calculated using math.log() so the exact number
may be inprecise.
"""
def __init__(self):
self.bhash = None
self.bits_avail = 0
self.bits_used = 0.0
def from_bytes(self, buf: bytes):
"""
Initialize a Bhash from a bytes object
"""
self.bhash = int.from_bytes(buf, byteorder='big')
self.bits_avail = len(buf) * 8
self.bits_used = 0.0
def modulo(self, mod: int) -> int:
"""
Treat the hash as a bigint and divide it by mod. The hash is updated
with the division result while the module value is returned.
"""
self.bits_used += math.log(mod) / math.log(2)
if self.bits_used > self.bits_avail:
raise BhashException("Consumed all bits in hash")
r = self.bhash % mod
self.bhash //= mod
return r

View File

@ -0,0 +1,47 @@
#
# Requirements: argon2-cffi
#
import argon2
import argparse
import getpass
import sys
#
# WARNING: Changing any of the parameters below will affect password generation
#
# Default SALT to use; this cannot be random since passgeny must
# generate predictable passwords
PASSGENY_SALT_DEFAULT = b"Passgeny v1"
# Memory cost expresssed in kb
PASSGENY_ARGON2_MEMORY_COST = 8192
# Number of iterations
PASSGENY_ARGON2_TIME_COST = 6
# Number of parallel threads
PASSGENY_ARGON2_PARALLEL = 4
# Hash length - 512 bits by default
PASSGENY_ARGON2_HASH_LEN = 64
def argon2_hash(message):
return argon2.low_level.hash_secret_raw(
message,
PASSGENY_SALT_DEFAULT,
type = argon2.Type.ID,
memory_cost = PASSGENY_ARGON2_MEMORY_COST,
time_cost = PASSGENY_ARGON2_TIME_COST,
parallelism = PASSGENY_ARGON2_PARALLEL,
hash_len = PASSGENY_ARGON2_HASH_LEN)
def passgeny_hash(master_password, token_list):
message = b''
# Construct the message to be hashed
for x in token_list:
message += x.encode() + b'\0'
message += master_password.encode() + b'\0'
return argon2_hash(message)
mpw = getpass.getpass("Master password: ")
print(passgeny_hash(mpw, ("1", "2", "3")))

View File