add base36 and base58 multiformat output

* output cidv1 of key in base36 or base58
* fix rsa custom seed to concatenate p + q instead of adding it
* renamed output file format pb2 to p2p
This commit is contained in:
Yann Autissier 2022-10-01 03:13:35 +02:00
parent f1b4573294
commit 029f49be22
3 changed files with 201 additions and 149 deletions

291
keygen.py
View File

@ -24,6 +24,7 @@
# along with this program. If not, see <https://www.gnu.org/licenses/>. # along with this program. If not, see <https://www.gnu.org/licenses/>.
import argparse import argparse
import base36
import base58 import base58
import base64 import base64
import configparser import configparser
@ -62,7 +63,7 @@ class keygen:
self.parser.add_argument( self.parser.add_argument(
"-f", "-f",
"--format", "--format",
choices=['ewif', 'jwk', 'nacl','pb2','pem','pubsec','seed','wif'], choices=['ewif', 'jwk', 'nacl','p2p','pem','pubsec','seed','wif'],
default=None, default=None,
dest="format", dest="format",
help="output file format, default: pem (pkcs8)", help="output file format, default: pem (pkcs8)",
@ -77,7 +78,7 @@ class keygen:
"-i", "-i",
"--input", "--input",
dest="input", dest="input",
help="read ed25519 key from file FILE, autodetect format: {credentials,ewif,jwk,nacl,mnemonic,pb2,pubsec,seed,wif}", help="read ed25519 key from file FILE, autodetect format: {credentials,ewif,jwk,nacl,mnemonic,p2p,pem,pubsec,seed,wif}",
metavar='FILE', metavar='FILE',
) )
self.parser.add_argument( self.parser.add_argument(
@ -121,7 +122,7 @@ class keygen:
self.parser.add_argument( self.parser.add_argument(
"-t", "-t",
"--type", "--type",
choices=['b58mh','b64mh','base58','base64','duniter','ipfs','jwk'], choices=['b36mf', 'b58mf', 'b58mh','b64mh','base58','base64','duniter','ipfs','jwk'],
default="base58", default="base58",
dest="type", dest="type",
help="output text format, default: base58", help="output text format, default: base58",
@ -160,6 +161,18 @@ class keygen:
if hasattr(self.duniterpy, 'sk') and self.duniterpy.sk: if hasattr(self.duniterpy, 'sk') and self.duniterpy.sk:
clearmem(self.duniterpy.sk) clearmem(self.duniterpy.sk)
log.debug("cleared: keygen.duniterpy.sk") log.debug("cleared: keygen.duniterpy.sk")
if hasattr(self, 'ed25519_secret_b36mf') and self.ed25519_secret_b36mf:
clearmem(self.ed25519_secret_b36mf)
log.debug("cleared: keygen.ed25519_secret_b36mf")
if hasattr(self, 'ed25519_secret_b58mf') and self.ed25519_secret_b58mf:
clearmem(self.ed25519_secret_b58mf)
log.debug("cleared: keygen.ed25519_secret_b58mf")
if hasattr(self, 'ed25519_secret_b58mh') and self.ed25519_secret_b58mh:
clearmem(self.ed25519_secret_b58mh)
log.debug("cleared: keygen.ed25519_secret_b58mh")
if hasattr(self, 'ed25519_secret_b64mh') and self.ed25519_secret_b64mh:
clearmem(self.ed25519_secret_b64mh)
log.debug("cleared: keygen.ed25519_secret_b64mh")
if hasattr(self, 'ed25519_secret_base58') and self.ed25519_secret_base58: if hasattr(self, 'ed25519_secret_base58') and self.ed25519_secret_base58:
clearmem(self.ed25519_secret_base58) clearmem(self.ed25519_secret_base58)
log.debug("cleared: keygen.ed25519_secret_base58") log.debug("cleared: keygen.ed25519_secret_base58")
@ -169,12 +182,15 @@ class keygen:
if hasattr(self, 'ed25519_secret_bytes') and self.ed25519_secret_bytes: if hasattr(self, 'ed25519_secret_bytes') and self.ed25519_secret_bytes:
clearmem(self.ed25519_secret_bytes) clearmem(self.ed25519_secret_bytes)
log.debug("cleared: keygen.ed25519_secret_bytes") log.debug("cleared: keygen.ed25519_secret_bytes")
if hasattr(self, 'ed25519_secret_cidv1') and self.ed25519_secret_cidv1:
clearmem(self.ed25519_secret_cidv1)
log.debug("cleared: keygen.ed25519_secret_cidv1")
if hasattr(self, 'ed25519_secret_pem_pkcs8') and self.ed25519_secret_pem_pkcs8: if hasattr(self, 'ed25519_secret_pem_pkcs8') and self.ed25519_secret_pem_pkcs8:
clearmem(self.ed25519_secret_pem_pkcs8) clearmem(self.ed25519_secret_pem_pkcs8)
log.debug("cleared: keygen.ed25515_secret_pem_pkcs8") log.debug("cleared: keygen.ed25515_secret_pem_pkcs8")
if hasattr(self, 'ed25519_secret_protobuf') and self.ed25519_secret_protobuf: if hasattr(self, 'ed25519_secret_libp2p') and self.ed25519_secret_libp2p:
clearmem(self.ed25519_secret_protobuf) clearmem(self.ed25519_secret_libp2p)
log.debug("cleared: keygen.ed25515_secret_protobuf") log.debug("cleared: keygen.ed25515_secret_libp2p")
if hasattr(self, 'ed25519_seed_bytes') and self.ed25519_seed_bytes: if hasattr(self, 'ed25519_seed_bytes') and self.ed25519_seed_bytes:
clearmem(self.ed25519_seed_bytes) clearmem(self.ed25519_seed_bytes)
log.debug("cleared: keygen.ed25519_seed_bytes") log.debug("cleared: keygen.ed25519_seed_bytes")
@ -208,6 +224,37 @@ class keygen:
clearmem(self.username) clearmem(self.username)
log.debug("cleared: keygen.username") log.debug("cleared: keygen.username")
def _cli(self, argv):
args = self.parser.parse_args(argv)
vars(self).update(vars(args))
# display version
if args.version:
version()
sys.exit()
# define log format
log_format='%(asctime)s %(levelname)s: %(message)s'
log_datefmt='%Y/%m/%d %H:%M:%S'
if args.debug:
log_level='DEBUG'
elif args.quiet:
log_level='ERROR'
elif args.verbose:
log_level='INFO'
else:
log_level='WARNING'
log.basicConfig(format=log_format, datefmt=log_datefmt, level=log_level)
log.debug("keygen.run(%s)" % argv)
self._check_args(args)
self._load_config()
self.gpg = gpg.Context(armor=True, offline=True)
self.gpg.set_passphrase_cb(self.gpg_passphrase_cb)
self.ed25519_from(args)
method = getattr(self, f'do_{self.type}', self._invalid_type)
return method()
def _invalid_type(self): def _invalid_type(self):
log.debug("keygen._invalid_type()") log.debug("keygen._invalid_type()")
self.parser.error(f"type {self.type} is not valid.") self.parser.error(f"type {self.type} is not valid.")
@ -272,11 +319,11 @@ class keygen:
if not hasattr(self, 'duniterpy'): if not hasattr(self, 'duniterpy'):
self.duniterpy_from_ed25519_seed_bytes() self.duniterpy_from_ed25519_seed_bytes()
self.duniterpy.save_private_key(self.output) self.duniterpy.save_private_key(self.output)
elif self.format == 'pb2': elif self.format == 'p2p':
if not hasattr(self, 'ed25519_secret_protobuf'): if not hasattr(self, 'ed25519_secret_libp2p'):
self.protobuf_from_ed25519() self.libp2p_from_ed25519()
with open(self.output, "wb") as file: with open(self.output, "wb") as file:
file.write(self.ed25519_secret_protobuf) file.write(self.ed25519_secret_libp2p)
elif self.format == 'pubsec': elif self.format == 'pubsec':
if not hasattr(self, 'duniterpy'): if not hasattr(self, 'duniterpy'):
self.duniterpy_from_ed25519_seed_bytes() self.duniterpy_from_ed25519_seed_bytes()
@ -306,56 +353,57 @@ class keygen:
if self.keys or self.secret: if self.keys or self.secret:
print("%s" % ''.join([self.prefix * secret_key_prefix, secret_key])) print("%s" % ''.join([self.prefix * secret_key_prefix, secret_key]))
def _run(self, argv): def b36mf_from_cidv1(self):
args = self.parser.parse_args(argv) log.debug("keygen.b36mf_from_cidv1()")
vars(self).update(vars(args)) if not hasattr(self, 'ed25519_public_cidv1') or not hasattr(self, 'ed25519_secret_cidv1'):
self.cidv1_from_libp2p()
# display version
if args.version:
version()
sys.exit()
# define log format
log_format='%(asctime)s %(levelname)s: %(message)s'
log_datefmt='%Y/%m/%d %H:%M:%S'
if args.debug:
log_level='DEBUG'
elif args.quiet:
log_level='ERROR'
elif args.verbose:
log_level='INFO'
else:
log_level='WARNING'
log.basicConfig(format=log_format, datefmt=log_datefmt, level=log_level)
log.debug("keygen.run(%s)" % argv)
self._check_args(args)
self._load_config()
self.gpg = gpg.Context(armor=True, offline=True)
self.gpg.set_passphrase_cb(self.gpg_passphrase_cb)
self.ed25519_from(args)
method = getattr(self, f'do_{self.type}', self._invalid_type)
return method()
def b58mh_from_protobuf(self):
log.debug("keygen.b58mh_from_protobuf()")
try: try:
self.ed25519_public_b58mh = base58.b58encode(self.ed25519_public_protobuf).decode('ascii') self.ed25519_public_b36mf = 'k' + base36.dumps(int.from_bytes(self.ed25519_public_cidv1, byteorder='big'))
self.ed25519_secret_b58mh = base58.b58encode(self.ed25519_secret_protobuf).decode('ascii') self.ed25519_secret_b36mf = 'k' + base36.dumps(int.from_bytes(self.ed25519_secret_cidv1, byteorder='big'))
except Exception as e: except Exception as e:
log.error(f'Unable to get b58mh from protobuf: {e}') log.error(f'Unable to get b36mf from cidv1: {e}')
self._cleanup()
exit(2)
log.debug("keygen.ed25519_public_b36mf=%s" % self.ed25519_public_b36mf)
log.debug("keygen.ed25519_secret_b36mf=%s" % self.ed25519_secret_b36mf)
def b58mf_from_cidv1(self):
log.debug("keygen.b58mf_from_cidv1()")
if not hasattr(self, 'ed25519_public_cidv1') or not hasattr(self, 'ed25519_secret_cidv1'):
self.cidv1_from_libp2p()
try:
self.ed25519_public_b58mf = 'z' + base58.b58encode(self.ed25519_public_cidv1).decode('ascii')
self.ed25519_secret_b58mf = 'z' + base58.b58encode(self.ed25519_secret_cidv1).decode('ascii')
except Exception as e:
log.error(f'Unable to get b58mf from cidv1: {e}')
self._cleanup()
exit(2)
log.debug("keygen.ed25519_public_b58mf=%s" % self.ed25519_public_b58mf)
log.debug("keygen.ed25519_secret_b58mf=%s" % self.ed25519_secret_b58mf)
def b58mh_from_libp2p(self):
log.debug("keygen.b58mh_from_libp2p()")
if not hasattr(self, 'ed25519_public_libp2p') or not hasattr(self, 'ed25519_secret_libp2p'):
self.libp2p_from_ed25519()
try:
self.ed25519_public_b58mh = base58.b58encode(self.ed25519_public_libp2p).decode('ascii')
self.ed25519_secret_b58mh = base58.b58encode(self.ed25519_secret_libp2p).decode('ascii')
except Exception as e:
log.error(f'Unable to get b58mh from libp2p: {e}')
self._cleanup() self._cleanup()
exit(2) exit(2)
log.debug("keygen.ed25519_public_b58mh=%s" % self.ed25519_public_b58mh) log.debug("keygen.ed25519_public_b58mh=%s" % self.ed25519_public_b58mh)
log.debug("keygen.ed25519_secret_b58mh=%s" % self.ed25519_secret_b58mh) log.debug("keygen.ed25519_secret_b58mh=%s" % self.ed25519_secret_b58mh)
def b64mh_from_protobuf(self): def b64mh_from_libp2p(self):
log.debug("keygen.b64mh_from_protobuf()") log.debug("keygen.b64mh_from_libp2p()")
if not hasattr(self, 'ed25519_public_libp2p') or not hasattr(self, 'ed25519_secret_libp2p'):
self.libp2p_from_ed25519()
try: try:
self.ed25519_public_b64mh = base64.b64encode(self.ed25519_public_protobuf).decode('ascii') self.ed25519_public_b64mh = base64.b64encode(self.ed25519_public_libp2p).decode('ascii')
self.ed25519_secret_b64mh = base64.b64encode(self.ed25519_secret_protobuf).decode('ascii') self.ed25519_secret_b64mh = base64.b64encode(self.ed25519_secret_libp2p).decode('ascii')
except Exception as e: except Exception as e:
log.error(f'Unable to get b64mh from protobuf: {e}') log.error(f'Unable to get b64mh from libp2p: {e}')
self._cleanup() self._cleanup()
exit(2) exit(2)
log.debug("keygen.ed25519_public_b64mh=%s" % self.ed25519_public_b64mh) log.debug("keygen.ed25519_public_b64mh=%s" % self.ed25519_public_b64mh)
@ -385,16 +433,46 @@ class keygen:
log.debug("keygen.ed25519_public_base64=%s" % self.ed25519_public_base64) log.debug("keygen.ed25519_public_base64=%s" % self.ed25519_public_base64)
log.debug("keygen.ed25519_secret_base64=%s" % self.ed25519_secret_base64) log.debug("keygen.ed25519_secret_base64=%s" % self.ed25519_secret_base64)
def cidv1_from_libp2p(self):
log.debug("keygen.cidv1_from_libp2p()")
if not hasattr(self, 'ed25519_public_libp2p') or not hasattr(self, 'ed25519_secret_libp2p'):
self.libp2p_from_ed25519()
try:
# \x01: multicodec cid prefix = CIDv1
# \x72: multicodec content prefix = libp2p-key
self.ed25519_public_cidv1 = b'\x01\x72' + self.ed25519_public_libp2p
self.ed25519_secret_cidv1 = b'\x01\x72' + self.ed25519_secret_libp2p
except Exception as e:
log.error(f'Unable to get cidv1 from libp2p: {e}')
self._cleanup()
exit(2)
log.debug("keygen.ed25519_public_cidv1=%s" % self.ed25519_public_cidv1)
log.debug("keygen.ed25519_secret_cidv1=%s" % self.ed25519_secret_cidv1)
def do_b36mf(self):
log.debug("keygen.do_b36mf()")
self.libp2p_from_ed25519()
self.cidv1_from_libp2p()
self.b36mf_from_cidv1()
self._output(self.ed25519_public_b36mf, self.ed25519_secret_b36mf, 'pub: ', 'sec: ')
def do_b58mf(self):
log.debug("keygen.do_b58mf()")
self.libp2p_from_ed25519()
self.cidv1_from_libp2p()
self.b58mf_from_cidv1()
self._output(self.ed25519_public_b58mf, self.ed25519_secret_b58mf, 'pub: ', 'sec: ')
def do_b58mh(self): def do_b58mh(self):
log.debug("keygen.do_b58mh()") log.debug("keygen.do_b58mh()")
self.protobuf_from_ed25519() self.libp2p_from_ed25519()
self.b58mh_from_protobuf() self.b58mh_from_libp2p()
self._output(self.ed25519_public_b58mh, self.ed25519_secret_b58mh, 'pub: ', 'sec: ') self._output(self.ed25519_public_b58mh, self.ed25519_secret_b58mh, 'pub: ', 'sec: ')
def do_b64mh(self): def do_b64mh(self):
log.debug("keygen.do_b64mh()") log.debug("keygen.do_b64mh()")
self.protobuf_from_ed25519() self.libp2p_from_ed25519()
self.b64mh_from_protobuf() self.b64mh_from_libp2p()
self._output(self.ed25519_public_b64mh, self.ed25519_secret_b64mh, 'pub: ', 'sec: ') self._output(self.ed25519_public_b64mh, self.ed25519_secret_b64mh, 'pub: ', 'sec: ')
def do_base58(self): def do_base58(self):
@ -416,9 +494,9 @@ class keygen:
def do_ipfs(self): def do_ipfs(self):
log.debug("keygen.do_ipfs()") log.debug("keygen.do_ipfs()")
self.protobuf_from_ed25519() self.libp2p_from_ed25519()
self.b58mh_from_protobuf() self.b58mh_from_libp2p()
self.b64mh_from_protobuf() self.b64mh_from_libp2p()
self._output(self.ed25519_public_b58mh, self.ed25519_secret_b64mh, 'PeerID: ', 'PrivKEY: ') self._output(self.ed25519_public_b58mh, self.ed25519_secret_b64mh, 'PeerID: ', 'PrivKEY: ')
def do_jwk(self): def do_jwk(self):
@ -540,7 +618,7 @@ class keygen:
if len(lines) > 0: if len(lines) > 0:
line = lines[0].strip() line = lines[0].strip()
regex_dewif = re.compile(b'^\x00\x00\x00\x01\x00\x00\x00\x01') regex_dewif = re.compile(b'^\x00\x00\x00\x01\x00\x00\x00\x01')
regex_pb2 = re.compile(b'^\x08\x01\x12@') regex_p2p = re.compile(b'^\x08\x01\x12@')
if re.search(regex_dewif, line): if re.search(regex_dewif, line):
log.info("input file format detected: dewif") log.info("input file format detected: dewif")
if not self.password: if not self.password:
@ -556,10 +634,10 @@ class keygen:
self._cleanup() self._cleanup()
exit(1) exit(1)
self.duniterpy = duniterpy.key.SigningKey.from_dewif_file(self.input, self.password) self.duniterpy = duniterpy.key.SigningKey.from_dewif_file(self.input, self.password)
if re.search(regex_pb2, line): if re.search(regex_p2p, line):
log.info("input file format detected: pb2") log.info("input file format detected: p2p")
self.ed25519_secret_protobuf = line self.ed25519_secret_libp2p = line
self.ed25519_seed_bytes_from_protobuf() self.ed25519_seed_bytes_from_libp2p()
self.duniterpy_from_ed25519_seed_bytes() self.duniterpy_from_ed25519_seed_bytes()
else: else:
raise NotImplementedError('unknown input file format.') raise NotImplementedError('unknown input file format.')
@ -714,25 +792,27 @@ class keygen:
if self.pgpy_key_type == 'RSA': if self.pgpy_key_type == 'RSA':
log.debug("keygen.pgpy._key.keymaterial.p=%s" % self.pgpy._key.keymaterial.p) log.debug("keygen.pgpy._key.keymaterial.p=%s" % self.pgpy._key.keymaterial.p)
log.debug("keygen.pgpy._key.keymaterial.q=%s" % self.pgpy._key.keymaterial.q) log.debug("keygen.pgpy._key.keymaterial.q=%s" % self.pgpy._key.keymaterial.q)
# custom seed: use sha256 hash of (p + q) # rsa custom seed: sha256 hash of (p + q), where + is a string concatenation
self.ed25519_seed_bytes = nacl.bindings.crypto_hash_sha256(long_to_bytes(self.pgpy._key.keymaterial.p + self.pgpy._key.keymaterial.q)) rsa_int = int(str(self.pgpy._key.keymaterial.p) + str(self.pgpy._key.keymaterial.q))
rsa_len = (rsa_int.bit_length() + 7) // 8
self.ed25519_seed_bytes = nacl.bindings.crypto_hash_sha256((rsa_int).to_bytes(rsa_len,byteorder='big'))
elif self.pgpy_key_type in ('ECDSA', 'EdDSA', 'ECDH'): elif self.pgpy_key_type in ('ECDSA', 'EdDSA', 'ECDH'):
log.debug("keygen.pgpy._key.keymaterial.s=%s" % self.pgpy._key.keymaterial.s) log.debug("keygen.pgpy._key.keymaterial.s=%s" % self.pgpy._key.keymaterial.s)
self.ed25519_seed_bytes = long_to_bytes(self.pgpy._key.keymaterial.s) self.ed25519_seed_bytes = self.pgpy._key.keymaterial.s.to_bytes(32, byteorder='big')
else: else:
raise NotImplementedError(f"getting seed from {self.pgpy_key_type} key is not implemented") raise NotImplementedError(f"getting seed from pgp key type {self.pgpy_key_type} is not implemented")
except Exception as e: except Exception as e:
log.error(f'Unable to get ed25519 seed bytes from pgpy: {e}') log.error(f'Unable to get ed25519 seed bytes from pgpy: {e}')
self._cleanup() self._cleanup()
exit(2) exit(2)
log.debug("keygen.ed25519_seed_bytes=%s" % self.ed25519_seed_bytes) log.debug("keygen.ed25519_seed_bytes=%s" % self.ed25519_seed_bytes)
def ed25519_seed_bytes_from_protobuf(self): def ed25519_seed_bytes_from_libp2p(self):
log.debug("keygen.ed25519_seed_bytes_from_protobuf()") log.debug("keygen.ed25519_seed_bytes_from_libp2p()")
try: try:
self.ed25519_seed_bytes = self.ed25519_secret_protobuf.lstrip(b'\x08\x01\x12@')[:32] self.ed25519_seed_bytes = self.ed25519_secret_libp2p.lstrip(b'\x08\x01\x12@')[:32]
except Exception as e: except Exception as e:
log.error(f'Unable to get ed25519 seed bytes from protobuf: {e}') log.error(f'Unable to get ed25519 seed bytes from libp2p: {e}')
self._cleanup() self._cleanup()
exit(2) exit(2)
log.debug("keygen.ed25519_seed_bytes=%s" % self.ed25519_seed_bytes) log.debug("keygen.ed25519_seed_bytes=%s" % self.ed25519_seed_bytes)
@ -826,73 +906,26 @@ class keygen:
self.pgpy_key_type = 'undefined' self.pgpy_key_type = 'undefined'
log.debug("keygen.pgpy_key_type=%s" % self.pgpy_key_type) log.debug("keygen.pgpy_key_type=%s" % self.pgpy_key_type)
def protobuf_from_ed25519(self): def libp2p_from_ed25519(self):
# libp2p protobuf version 2 # libp2p protobuf version 2
log.debug("keygen.protobuf_from_ed25519()") log.debug("keygen.libp2p_from_ed25519()")
try: try:
self.ed25519_public_protobuf = b'\x00$\x08\x01\x12 ' + self.ed25519_public_bytes # \x00: multihash prefix = id
self.ed25519_secret_protobuf = b'\x08\x01\x12@' + self.ed25519_secret_bytes # \x24: multihash length = 36 bytes
self.ed25519_public_libp2p = b'\x00$\x08\x01\x12 ' + self.ed25519_public_bytes
self.ed25519_secret_libp2p = b'\x08\x01\x12@' + self.ed25519_secret_bytes
except Exception as e: except Exception as e:
log.error(f'Unable to get protobuf from ed25519: {e}') log.error(f'Unable to get libp2p from ed25519: {e}')
self._cleanup() self._cleanup()
exit(2) exit(2)
log.debug("keygen.ed25519_public_protobuf=%s" % self.ed25519_public_protobuf) log.debug("keygen.ed25519_public_libp2p=%s" % self.ed25519_public_libp2p)
log.debug("keygen.ed25519_secret_protobuf=%s" % self.ed25519_secret_protobuf) log.debug("keygen.ed25519_secret_libp2p=%s" % self.ed25519_secret_libp2p)
##
# long_to_bytes comes from PyCrypto, which is released into Public Domain
# https://github.com/dlitz/pycrypto/blob/master/lib/Crypto/Util/number.py
def bytes_to_long(s):
"""bytes_to_long(string) : long
Convert a byte string to a long integer.
This is (essentially) the inverse of long_to_bytes().
"""
acc = 0
unpack = struct.unpack
length = len(s)
if length % 4:
extra = (4 - length % 4)
s = b'\000' * extra + s
length = length + extra
for i in range(0, length, 4):
acc = (acc << 32) + unpack('>I', s[i:i+4])[0]
return acc
def long_to_bytes(n, blocksize=0):
"""long_to_bytes(n:long, blocksize:int) : string
Convert a long integer to a byte string.
If optional blocksize is given and greater than zero, pad the front of the
byte string with binary zeros so that the length is a multiple of
blocksize.
"""
# after much testing, this algorithm was deemed to be the fastest
s = b''
n = int(n)
pack = struct.pack
while n > 0:
s = pack('>I', n & 0xffffffff) + s
n = n >> 32
# strip off leading zeros
for i in range(len(s)):
if s[i] != b'\000'[0]:
break
else:
# only happens when n == 0
s = b'\000'
i = 0
s = s[i:]
# add back some pad bytes. this could be done more efficiently w.r.t. the
# de-padding being done above, but sigh...
if blocksize > 0 and len(s) % blocksize:
s = (blocksize - len(s) % blocksize) * b'\000' + s
return s
def main(argv=None): def main(argv=None):
if argv is None: if argv is None:
argv = sys.argv[1:] argv = sys.argv[1:]
return keygen()._cli(argv)
cli = keygen()
return cli._run(argv)
def version(version=__version__): def version(version=__version__):
print("%s v%s" % (sys.argv[0],version)) print("%s v%s" % (sys.argv[0],version))

View File

@ -1,3 +1,4 @@
base36==0.1.1
base58==2.1.1 base58==2.1.1
cryptography==3.4.8 cryptography==3.4.8
duniterpy==1.1.0 duniterpy==1.1.0

View File

@ -6,7 +6,7 @@ DUBP_FILE="${SHELLSPEC_TMPBASE}/mnemonic"
EWIF_FILE="${SHELLSPEC_TMPBASE}/username.ewif" EWIF_FILE="${SHELLSPEC_TMPBASE}/username.ewif"
JWK_FILE="${SHELLSPEC_TMPBASE}/username.jwk" JWK_FILE="${SHELLSPEC_TMPBASE}/username.jwk"
NACL_FILE="${SHELLSPEC_TMPBASE}/username.nacl" NACL_FILE="${SHELLSPEC_TMPBASE}/username.nacl"
PB2_FILE="${SHELLSPEC_TMPBASE}/username.pb2" P2P_FILE="${SHELLSPEC_TMPBASE}/username.p2p"
PEM_FILE="${SHELLSPEC_TMPBASE}/username.pem" PEM_FILE="${SHELLSPEC_TMPBASE}/username.pem"
PUBSEC_FILE="${SHELLSPEC_TMPBASE}/username.pubsec" PUBSEC_FILE="${SHELLSPEC_TMPBASE}/username.pubsec"
SEED_FILE="${SHELLSPEC_TMPBASE}/username.seed" SEED_FILE="${SHELLSPEC_TMPBASE}/username.seed"
@ -113,6 +113,24 @@ Describe 'keygen'
The stderr should equal "" The stderr should equal ""
End End
End End
Describe '-pkt b36mf username password:'
It 'prints prefixed base36 multiformat public and secret keys for user "username" and password "password"'
When run keygen -pkt b36mf username password
The output should include 'pub: k51qzi5uqu5dhhsbw068pust1xf763zdmyu2mb8rf6ewu2oz3in3a2g6pgtqy3'
The output should include 'sec: kmxn88f5mep5chc4tc002gyhtl9vgiluellgje285y2hn5a5kjdvqge7oeb0jryupt1q09w48h2nxg0ofcjco0wjwa824v3p9tvw6us9gdkb'
The status should be success
The stderr should equal ""
End
End
Describe '-pkt b58mf username password:'
It 'prints prefixed base58 multiformat public and secret keys for user "username" and password "password"'
When run keygen -pkt b58mf username password
The output should include 'pub: z5AanNVJCxnJNiidpTZyuYzkQcrHRCyhxMV7Z4KYDV1MYy2ETMrEbUn'
The output should include 'sec: z4gg7xjCuszBpvNVcDAmNYVNrZxwXfDDQGoAShWmmQBkWRzZbR8A4ZBpkk4iTj3YSLBxvGZRf1AjCyGDdczhs7tshCsbFK4e'
The status should be success
The stderr should equal ""
End
End
Describe '-pkt b58mh username password:' Describe '-pkt b58mh username password:'
It 'prints prefixed base58 multihash public and secret keys for user "username" and password "password"' It 'prints prefixed base58 multihash public and secret keys for user "username" and password "password"'
When run keygen -pkt b58mh username password When run keygen -pkt b58mh username password
@ -303,34 +321,34 @@ Describe 'keygen'
End End
rm -f "${PEM_FILE}" rm -f "${PEM_FILE}"
End End
Describe "-f pb2 -o ${PB2_FILE} username password:" Describe "-f p2p -o ${P2P_FILE} username password:"
rm -f "${PB2_FILE}" rm -f "${P2P_FILE}"
It 'writes protobuf2 secret key to a pb2 file for user "username" and password "password"' It 'writes libp2p secret key to a p2p file for user "username" and password "password"'
decode_pb2() { decode_p2p() {
xxd -p "${PB2_FILE}" xxd -p "${P2P_FILE}"
} }
not_xxd() { not_xxd() {
! which xxd >/dev/null 2>&1 ! which xxd >/dev/null 2>&1
} }
Skip if 'You should install xxd' not_xxd Skip if 'You should install xxd' not_xxd
When run keygen -f pb2 -o "${PB2_FILE}" username password When run keygen -f p2p -o "${P2P_FILE}" username password
The path "${PB2_FILE}" should exist The path "${P2P_FILE}" should exist
The result of function decode_pb2 should include '080112400f97a825a346a0a335ef68537400efde9b107f93fabc60c8f43f' The result of function decode_p2p should include '080112400f97a825a346a0a335ef68537400efde9b107f93fabc60c8f43f'
The result of function decode_pb2 should include '1245ef13632f349a136ef70ffa6e75f97c31ae65aa1da3a9235643d144b0' The result of function decode_p2p should include '1245ef13632f349a136ef70ffa6e75f97c31ae65aa1da3a9235643d144b0'
The result of function decode_pb2 should include '2e3a80995f01a1ab' The result of function decode_p2p should include '2e3a80995f01a1ab'
The status should be success The status should be success
The stderr should equal "" The stderr should equal ""
End End
End End
Describe "-pki ${PB2_FILE}:" Describe "-pki ${P2P_FILE}:"
It 'prints prefixed base58 public and secret keys for ed25519 key read from pb2 file"' It 'prints prefixed base58 public and secret keys for ed25519 key read from p2p file"'
When run keygen -pki "${PB2_FILE}" -v When run keygen -pki "${P2P_FILE}" -v
The output should include 'pub: 4YLU1xQ9jzb7LzC6d91VZrYTEKS9N2j93Nnvcee6wxZG' The output should include 'pub: 4YLU1xQ9jzb7LzC6d91VZrYTEKS9N2j93Nnvcee6wxZG'
The output should include 'sec: K5heSX4xGUPtRbxcZh6zbgaKbDv8FeVc9JuSNWtUs7C1oGNKqv7kQJ3DHdouTPzoW4duKKnuLQK8LbHKfN9fkjC' The output should include 'sec: K5heSX4xGUPtRbxcZh6zbgaKbDv8FeVc9JuSNWtUs7C1oGNKqv7kQJ3DHdouTPzoW4duKKnuLQK8LbHKfN9fkjC'
The status should be success The status should be success
The stderr should include 'input file format detected: pb2' The stderr should include 'input file format detected: p2p'
End End
rm -f "${PB2_FILE}" rm -f "${P2P_FILE}"
End End
Describe "-f pubsec -o ${PUBSEC_FILE} username password:" Describe "-f pubsec -o ${PUBSEC_FILE} username password:"
rm -f "${PUBSEC_FILE}" rm -f "${PUBSEC_FILE}"
@ -454,8 +472,8 @@ Describe 'keygen'
gpg --batch --import --quiet specs/usersame.asc gpg --batch --import --quiet specs/usersame.asc
It 'prints prefixed base58 public and secret keys for rsa gpg key matching uid "usersame"' It 'prints prefixed base58 public and secret keys for rsa gpg key matching uid "usersame"'
When run keygen -pkg usersame When run keygen -pkg usersame
The output should include 'pub: 4NxSjjys6bo8mhM919MkvNkNPFu4zpFyxu1r7yJ39K87' The output should include 'pub: EGdSY9fKom7MnvHALNQU7LUoEEE2sju5ntL9eRXJ5tTM'
The output should include 'sec: 2cLFNeXiqcKKv5BF9JVTwtWmFHLvjDkJkrCyQbST9oYbsQLHsVaUAzbwrv5YfzQcPHu6e6XUzdstKy4kLhgDSGiw' The output should include 'sec: 4jPG9MH9LVA7HhcfFs41pXVjxDQLdgu3Mtc64Ph6U3vUMNWfJqTBdFFaviq5r6zJC8PpWUiaUhjVnYAa2E9UrFTZ'
The status should be success The status should be success
The stderr should equal "" The stderr should equal ""
End End
@ -465,8 +483,8 @@ Describe 'keygen'
gpg --batch --import --quiet specs/usersame_protected.asc gpg --batch --import --quiet specs/usersame_protected.asc
It 'prints prefixed public and secret keys for rsa gpg key matching uid "usersame@protected" and locked with password "password"' It 'prints prefixed public and secret keys for rsa gpg key matching uid "usersame@protected" and locked with password "password"'
When run keygen -pkg usersame@protected password When run keygen -pkg usersame@protected password
The output should include 'pub: 5kh2uqNTuYsLN7fwSRP3JWM4Hotcpdkb7frRNZwo9BPp' The output should include 'pub: 6KNNPBxkMYnccYvpePBKDewZ3JiQnmWA4e7QSsvZUzLM'
The output should include 'sec: LdWjjkP7gRzH4k4gNkQs2er26bE2Dhz7cGPE8fMNixe1Uv2ZHbo1QtyZxmDeTP77y6HVLbHNoXdMTHdo6ip9PHk' The output should include 'sec: 4q4SM9qoWc2eLtfYWs7K9hb7oSCNjCLc8U6ELNrScteVGVnSBP4YMDM5V8RPsHURqCqP5ndPkqGoB74cmRxfJro7'
The status should be success The status should be success
The stderr should equal "" The stderr should equal ""
End End