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:
parent
f1b4573294
commit
029f49be22
291
keygen.py
291
keygen.py
|
@ -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))
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue