lang/python/ PgenPasswordGenerator


See also PgenKivy, PgenQt and PgenCs

=== Pgen version 1 Equivalent of the following on a standard Gnu command line {{c echo "$input$secret" | md5sum | cut -c1-32 | base64 | cut -c1-16 | tr "+/" "@#" }}

{{c

!/usr/bin/env python3

import hashlib import base64 import sys args = sys.argv[1:] import os env = os.environ

def hash(x): 'Takes bytes x and returns md5 digest as bytes' x = x + b"\n" m = hashlib.md5() m.update(x) return m.hexdigest().encode("utf8") def b64(x): 'Takes bytes x and returns base64 encoding as string' return base64.b64encode(x).decode("utf8") def tr(x): 'equivalent of tr "+/" "@#"' return x.replace("/","@").replace("+","#") def comb(i,s,schema=b"$I$S"): return schema.replace(b"$I",i).replace(b"$S",s) def j(i,s,schema="$I$S"): i = i.encode("utf8") s = s.encode("utf8") schema = schema.encode("utf8") return tr(b64(hash(comb(i,s,schema))))

s = os.getenv("S","") for x in args: print(j(x,s)[:16]) }} This version has a few flaws, in particular omitting the 'xxd -r -p' to convert the hex string output by md5sum to binary before feeding it through base64. Thus the 16 character string output only captures half the entropy it should. Another is a relic of the bash version, and in particular the missing '-n' on the echo command. The javascript implementation of this (versions 1 and 2) at https://sec.allsup.co/jj?inputString keeps these flaws when in Md5n mode. The version 1 implementation is also at https://sec.allsup.co/j?inputString .

=== Pgen version 2 Equivalent of the following on a standard Gnu command line. Javascript implementation at http://sec.allsup.co/jj?inputString {{c echo "$input$secret" | sha256sum | cut -c1-64 | xxd -r -p | base64 | cut -c1-16 | tr "+/" "@#" }}

{{c

!/usr/bin/env python3

import hashlib import base64 import sys args = sys.argv[1:] import os env = os.environ

def hash(x): 'Takes bytes x and returns sha256 digest as bytes' m = hashlib.sha256() m.update(x) return m.digest() def b64(x): 'Takes bytes x and returns base64 encoding as string' return base64.b64encode(x).decode("utf8") def tr(x): 'equivalent of tr "+/" "@#"' return x.replace("+","@").replace("/","#") def comb(i,s,schema=b"$I$S"): return schema.replace(b"$I",i).replace(b"$S",s) def jj(i,s,schema="$I$S"): i = i.encode("utf8") s = s.encode("utf8") schema = schema.encode("utf8") return tr(b64(hash(comb(i,s,schema))))

s = os.getenv("S","") for x in args: print(jj(x,s)[:16]) }}

=== Pgen version 3 No bash command line equivalent, uses sha256 function iteratively 16384*n times where n is the length of the sequence (here the sequence is "in principio erat verbum et verbum erat apud deum et deus erat verbum") {{c

!/usr/bin/env python3

import hashlib import base64 import sys args = sys.argv[1:] import os env = os.environ

john1 = "in principio erat verbum et verbum erat apud deum et deus erat verbum".encode("utf8").split(b" ")

def hash(x): 'Takes bytes x and returns sha256 digest as bytes' m = hashlib.sha256() m.update(x) return m.digest() def jjjs(inp,sec,seq,n=16384): "inp cur seq are bytes() objects" x =inp for i in range(n): for t in seq: x = hash(b"".join((t,sec,inp,x,sec,t))) return x def jjjt(inp,sec): return jjjs(inp,sec,john1)

def b64(x): 'Takes bytes x and returns base64 encoding as string' return base64.b64encode(x).decode("utf8") def tr(x): 'equivalent of tr "+/" "@#"' return x.replace("+","@").replace("/","#")

def jjj(inp,sec,n=16): return tr(b64(jjjt(inp,sec)))[:n]

s = os.getenv("S","").encode("utf8") for x in args: print(jjj(x.encode("utf8"),s)) }}

And if one wishes to have multiple 'secret' phrases, it is simple enough to append them to the sequence. Basically the idea here is to make a more processor intensive hashing function out of sha256. In addition, one can change the hash function to anything else. The key is that the process is //repeatable//. The versions 1 and 2 have the nice property that they can be expressed as a 1-line bash command (indeed, it works with /bin/dash too). In practice, version 2 is fine for most things, and version 3 is perhaps overkill.

=== Pgen version 3.1 I figure it is easier to iterate the {{x -> sha256 -> base64 -> x}} loop rather than something fancy like a sequence of words.

{{c

!/usr/bin/env python3

import hashlib import base64 import sys args = sys.argv[1:] import os env = os.environ

helpers for iterating sha

def sha256(x, coding='utf8'): return sha256_real(x.encode(coding)).decode(coding) def sha256_real(x): sha = hashlib.sha256() sha.update(x) return base64.b64encode(sha.digest()) def sha_multi_round(x,n, coding='utf8'): return sha_multi_round_real(x.encode(coding),n).decode(coding) def sha_multi_round_real(x,n): for j in range(n): x = sha256_real(x) return x

def b64(x): 'Takes bytes x and returns base64 encoding as string' return base64.b64encode(x).decode("utf8") def tr(x): 'equivalent of tr "+/" "@#"' return x.replace("+","@").replace("/","#")

def jjj(inp,sec,n=16384,l=16): return tr(sha_multi_round(inp+sec,n))[:l]

s = os.getenv("S","") for x in args: print(jjj(x,s)) }}

And one can check that this is functionally identical to the javascript version at https://sec.allsup.co/jjj?MrFlibble%TIME=1619380223