See also PgenKivy, PgenQt and PgenCs
Pgen version 1
Equivalent of the following on a standard Gnu command line
echo "$input$secret" | md5sum | cut -c1-32 | base64 | cut -c1-16 | tr "+/" "@#"
#!/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) keeps these flaws when in Md5n mode.
Pgen version 2
Equivalent of the following on a standard Gnu command line.
echo "$input$secret" | sha256sum | cut -c1-64 | xxd -r -p | base64 | cut -c1-16 | tr "+/" "@#"
#!/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")
#!/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.
#!/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))