wip: refacto
This commit is contained in:
parent
029f49be22
commit
fb08e6ed65
162
crypto_pb2.py
162
crypto_pb2.py
|
@ -1,162 +0,0 @@
|
||||||
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
|
||||||
# source: crypto.proto
|
|
||||||
|
|
||||||
import sys
|
|
||||||
_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1'))
|
|
||||||
from google.protobuf.internal import enum_type_wrapper
|
|
||||||
from google.protobuf import descriptor as _descriptor
|
|
||||||
from google.protobuf import message as _message
|
|
||||||
from google.protobuf import reflection as _reflection
|
|
||||||
from google.protobuf import symbol_database as _symbol_database
|
|
||||||
# @@protoc_insertion_point(imports)
|
|
||||||
|
|
||||||
_sym_db = _symbol_database.Default()
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
DESCRIPTOR = _descriptor.FileDescriptor(
|
|
||||||
name='crypto.proto',
|
|
||||||
package='crypto.pb',
|
|
||||||
syntax='proto2',
|
|
||||||
serialized_options=_b('Z*github.com/libp2p/go-libp2p-core/crypto/pb'),
|
|
||||||
serialized_pb=_b('\n\x0c\x63rypto.proto\x12\tcrypto.pb\";\n\tPublicKey\x12 \n\x04Type\x18\x01 \x02(\x0e\x32\x12.crypto.pb.KeyType\x12\x0c\n\x04\x44\x61ta\x18\x02 \x02(\x0c\"<\n\nPrivateKey\x12 \n\x04Type\x18\x01 \x02(\x0e\x32\x12.crypto.pb.KeyType\x12\x0c\n\x04\x44\x61ta\x18\x02 \x02(\x0c*9\n\x07KeyType\x12\x07\n\x03RSA\x10\x00\x12\x0b\n\x07\x45\x64\x32\x35\x35\x31\x39\x10\x01\x12\r\n\tSecp256k1\x10\x02\x12\t\n\x05\x45\x43\x44SA\x10\x03\x42,Z*github.com/libp2p/go-libp2p-core/crypto/pb')
|
|
||||||
)
|
|
||||||
|
|
||||||
_KEYTYPE = _descriptor.EnumDescriptor(
|
|
||||||
name='KeyType',
|
|
||||||
full_name='crypto.pb.KeyType',
|
|
||||||
filename=None,
|
|
||||||
file=DESCRIPTOR,
|
|
||||||
values=[
|
|
||||||
_descriptor.EnumValueDescriptor(
|
|
||||||
name='RSA', index=0, number=0,
|
|
||||||
serialized_options=None,
|
|
||||||
type=None),
|
|
||||||
_descriptor.EnumValueDescriptor(
|
|
||||||
name='Ed25519', index=1, number=1,
|
|
||||||
serialized_options=None,
|
|
||||||
type=None),
|
|
||||||
_descriptor.EnumValueDescriptor(
|
|
||||||
name='Secp256k1', index=2, number=2,
|
|
||||||
serialized_options=None,
|
|
||||||
type=None),
|
|
||||||
_descriptor.EnumValueDescriptor(
|
|
||||||
name='ECDSA', index=3, number=3,
|
|
||||||
serialized_options=None,
|
|
||||||
type=None),
|
|
||||||
],
|
|
||||||
containing_type=None,
|
|
||||||
serialized_options=None,
|
|
||||||
serialized_start=150,
|
|
||||||
serialized_end=207,
|
|
||||||
)
|
|
||||||
_sym_db.RegisterEnumDescriptor(_KEYTYPE)
|
|
||||||
|
|
||||||
KeyType = enum_type_wrapper.EnumTypeWrapper(_KEYTYPE)
|
|
||||||
RSA = 0
|
|
||||||
Ed25519 = 1
|
|
||||||
Secp256k1 = 2
|
|
||||||
ECDSA = 3
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
_PUBLICKEY = _descriptor.Descriptor(
|
|
||||||
name='PublicKey',
|
|
||||||
full_name='crypto.pb.PublicKey',
|
|
||||||
filename=None,
|
|
||||||
file=DESCRIPTOR,
|
|
||||||
containing_type=None,
|
|
||||||
fields=[
|
|
||||||
_descriptor.FieldDescriptor(
|
|
||||||
name='Type', full_name='crypto.pb.PublicKey.Type', index=0,
|
|
||||||
number=1, type=14, cpp_type=8, label=2,
|
|
||||||
has_default_value=False, default_value=0,
|
|
||||||
message_type=None, enum_type=None, containing_type=None,
|
|
||||||
is_extension=False, extension_scope=None,
|
|
||||||
serialized_options=None, file=DESCRIPTOR),
|
|
||||||
_descriptor.FieldDescriptor(
|
|
||||||
name='Data', full_name='crypto.pb.PublicKey.Data', index=1,
|
|
||||||
number=2, type=12, cpp_type=9, label=2,
|
|
||||||
has_default_value=False, default_value=_b(""),
|
|
||||||
message_type=None, enum_type=None, containing_type=None,
|
|
||||||
is_extension=False, extension_scope=None,
|
|
||||||
serialized_options=None, file=DESCRIPTOR),
|
|
||||||
],
|
|
||||||
extensions=[
|
|
||||||
],
|
|
||||||
nested_types=[],
|
|
||||||
enum_types=[
|
|
||||||
],
|
|
||||||
serialized_options=None,
|
|
||||||
is_extendable=False,
|
|
||||||
syntax='proto2',
|
|
||||||
extension_ranges=[],
|
|
||||||
oneofs=[
|
|
||||||
],
|
|
||||||
serialized_start=27,
|
|
||||||
serialized_end=86,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
_PRIVATEKEY = _descriptor.Descriptor(
|
|
||||||
name='PrivateKey',
|
|
||||||
full_name='crypto.pb.PrivateKey',
|
|
||||||
filename=None,
|
|
||||||
file=DESCRIPTOR,
|
|
||||||
containing_type=None,
|
|
||||||
fields=[
|
|
||||||
_descriptor.FieldDescriptor(
|
|
||||||
name='Type', full_name='crypto.pb.PrivateKey.Type', index=0,
|
|
||||||
number=1, type=14, cpp_type=8, label=2,
|
|
||||||
has_default_value=False, default_value=0,
|
|
||||||
message_type=None, enum_type=None, containing_type=None,
|
|
||||||
is_extension=False, extension_scope=None,
|
|
||||||
serialized_options=None, file=DESCRIPTOR),
|
|
||||||
_descriptor.FieldDescriptor(
|
|
||||||
name='Data', full_name='crypto.pb.PrivateKey.Data', index=1,
|
|
||||||
number=2, type=12, cpp_type=9, label=2,
|
|
||||||
has_default_value=False, default_value=_b(""),
|
|
||||||
message_type=None, enum_type=None, containing_type=None,
|
|
||||||
is_extension=False, extension_scope=None,
|
|
||||||
serialized_options=None, file=DESCRIPTOR),
|
|
||||||
],
|
|
||||||
extensions=[
|
|
||||||
],
|
|
||||||
nested_types=[],
|
|
||||||
enum_types=[
|
|
||||||
],
|
|
||||||
serialized_options=None,
|
|
||||||
is_extendable=False,
|
|
||||||
syntax='proto2',
|
|
||||||
extension_ranges=[],
|
|
||||||
oneofs=[
|
|
||||||
],
|
|
||||||
serialized_start=88,
|
|
||||||
serialized_end=148,
|
|
||||||
)
|
|
||||||
|
|
||||||
_PUBLICKEY.fields_by_name['Type'].enum_type = _KEYTYPE
|
|
||||||
_PRIVATEKEY.fields_by_name['Type'].enum_type = _KEYTYPE
|
|
||||||
DESCRIPTOR.message_types_by_name['PublicKey'] = _PUBLICKEY
|
|
||||||
DESCRIPTOR.message_types_by_name['PrivateKey'] = _PRIVATEKEY
|
|
||||||
DESCRIPTOR.enum_types_by_name['KeyType'] = _KEYTYPE
|
|
||||||
_sym_db.RegisterFileDescriptor(DESCRIPTOR)
|
|
||||||
|
|
||||||
PublicKey = _reflection.GeneratedProtocolMessageType('PublicKey', (_message.Message,), dict(
|
|
||||||
DESCRIPTOR = _PUBLICKEY,
|
|
||||||
__module__ = 'crypto_pb2'
|
|
||||||
# @@protoc_insertion_point(class_scope:crypto.pb.PublicKey)
|
|
||||||
))
|
|
||||||
_sym_db.RegisterMessage(PublicKey)
|
|
||||||
|
|
||||||
PrivateKey = _reflection.GeneratedProtocolMessageType('PrivateKey', (_message.Message,), dict(
|
|
||||||
DESCRIPTOR = _PRIVATEKEY,
|
|
||||||
__module__ = 'crypto_pb2'
|
|
||||||
# @@protoc_insertion_point(class_scope:crypto.pb.PrivateKey)
|
|
||||||
))
|
|
||||||
_sym_db.RegisterMessage(PrivateKey)
|
|
||||||
|
|
||||||
|
|
||||||
DESCRIPTOR._options = None
|
|
||||||
# @@protoc_insertion_point(module_scope)
|
|
310
dpgpid
310
dpgpid
|
@ -1,6 +1,6 @@
|
||||||
#!/bin/sh
|
#!/usr/bin/env python3
|
||||||
# link: https://git.p2p.legal/aya/dpgpid/
|
# link: https://git.p2p.legal/aya/dpgpid/
|
||||||
# desc: dpgpid (Decentralized PGP IDentifiers) shares PGP keys with DIDs on IPFS
|
# desc: generate did:ipid keys from gpg
|
||||||
|
|
||||||
# Copyleft 2022 Yann Autissier <aya@asycn.io>
|
# Copyleft 2022 Yann Autissier <aya@asycn.io>
|
||||||
|
|
||||||
|
@ -12,61 +12,273 @@
|
||||||
# This program is distributed in the hope that it will be useful,
|
# This program is distributed in the hope that it will be useful,
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
# GNU General Public License for more details.
|
# GNU Affero General Public License for more details.
|
||||||
|
|
||||||
# You should have received a copy of the GNU Affero General Public License
|
# You should have received a copy of the GNU Affero General Public License
|
||||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
set -eu
|
import argparse
|
||||||
|
import configparser
|
||||||
|
import gpg
|
||||||
|
import json
|
||||||
|
import logging as log
|
||||||
|
from SecureBytes import clearmem
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
import struct
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
import warnings
|
||||||
|
|
||||||
DATE=$(date -u +%FT%TZ%Z)
|
sys.path.append(os.path.abspath('../py-ipfs-http-client/'))
|
||||||
USAGE='[--help] [--version] list'
|
import ipfshttpclient
|
||||||
VERSION='0.0.1'
|
import key
|
||||||
|
|
||||||
dpgpid() {
|
__version__='0.1.0'
|
||||||
while test $# != 0; do
|
|
||||||
case "$1" in
|
|
||||||
-h|--help)
|
|
||||||
help
|
|
||||||
;;
|
|
||||||
-v|--version)
|
|
||||||
version
|
|
||||||
;;
|
|
||||||
--)
|
|
||||||
shift
|
|
||||||
break
|
|
||||||
;;
|
|
||||||
-*)
|
|
||||||
usage
|
|
||||||
;;
|
|
||||||
list)
|
|
||||||
list
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
break
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
shift
|
|
||||||
done
|
|
||||||
}
|
|
||||||
|
|
||||||
help() {
|
class dpgpid:
|
||||||
usage
|
def __init__(self):
|
||||||
}
|
self.parser = argparse.ArgumentParser(description="""
|
||||||
|
Generate did:ipid keys from gpg.
|
||||||
|
It converts a gpg key to a Decentralized IDentifier.""")
|
||||||
|
self.parser.add_argument(
|
||||||
|
'action',
|
||||||
|
help="{list,publish}",
|
||||||
|
nargs="?",
|
||||||
|
)
|
||||||
|
self.parser.add_argument(
|
||||||
|
"-d",
|
||||||
|
"--debug",
|
||||||
|
action="store_true",
|
||||||
|
help="show debug informations",
|
||||||
|
)
|
||||||
|
self.parser.add_argument(
|
||||||
|
"-q",
|
||||||
|
"--quiet",
|
||||||
|
action="store_true",
|
||||||
|
help="show only errors",
|
||||||
|
)
|
||||||
|
self.parser.add_argument(
|
||||||
|
"-t",
|
||||||
|
"--type",
|
||||||
|
choices=['dns', 'ipid','key'],
|
||||||
|
default="ipid",
|
||||||
|
dest="type",
|
||||||
|
help="did output format, default: ipid",
|
||||||
|
)
|
||||||
|
self.parser.add_argument(
|
||||||
|
"-v",
|
||||||
|
"--verbose",
|
||||||
|
action="store_true",
|
||||||
|
help="show more informations",
|
||||||
|
)
|
||||||
|
self.parser.add_argument(
|
||||||
|
"--version",
|
||||||
|
action="store_true",
|
||||||
|
help="show version and exit",
|
||||||
|
)
|
||||||
|
self.parser.add_argument(
|
||||||
|
'-u',
|
||||||
|
'--username',
|
||||||
|
dest="username",
|
||||||
|
)
|
||||||
|
self.parser.add_argument(
|
||||||
|
'-p',
|
||||||
|
'--password',
|
||||||
|
dest="password",
|
||||||
|
)
|
||||||
|
|
||||||
list() {
|
def _check_args(self, args):
|
||||||
gpg --list-secret-keys --with-colons |awk -F: '$1 == "sec" {print $5}' |while read key; do
|
log.debug("dpgpid._check_args(%s)" % args)
|
||||||
id=$(keygen -t ipfs -g ${key} 2>/dev/null) && printf "did:ipid:${id}\n" ||
|
if self.action not in ['list', 'publish']:
|
||||||
echo "ERROR: Unable to extract id from key ${key}"
|
self.parser.error('dpgpid requires a valid action')
|
||||||
done
|
|
||||||
}
|
|
||||||
|
|
||||||
usage() {
|
def _cleanup(self):
|
||||||
printf "%s\n" "Usage: $(basename "$0") ${USAGE}"
|
log.debug("dpgpid._cleanup()")
|
||||||
}
|
self.ipfs.close()
|
||||||
|
|
||||||
version() {
|
def _cli(self, argv):
|
||||||
printf "%s\n" "Version: $(basename "$0") v${VERSION}"
|
args = self.parser.parse_args(argv)
|
||||||
}
|
vars(self).update(vars(args))
|
||||||
|
|
||||||
dpgpid "$@"
|
# 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)
|
||||||
|
|
||||||
|
self._check_args(args)
|
||||||
|
self._load_config()
|
||||||
|
self.gpg = gpg.Context(armor=True, offline=True)
|
||||||
|
try:
|
||||||
|
self.ipfs = ipfshttpclient.connect('/ip4/172.18.0.2/tcp/5001/',session=True,timeout=3)
|
||||||
|
except Exception as e:
|
||||||
|
log.error('Unable to load ipfs client: %s' % e)
|
||||||
|
exit(2)
|
||||||
|
method = getattr(self, f'do_{self.type}', self._invalid_type)
|
||||||
|
return method()
|
||||||
|
|
||||||
|
def _invalid_type(self):
|
||||||
|
log.debug("dpgpid._invalid_type()")
|
||||||
|
self.parser.error(f"type {self.type} is not valid.")
|
||||||
|
|
||||||
|
def _load_config(self):
|
||||||
|
log.debug("dpgpid._load_config()")
|
||||||
|
self.config = configparser.RawConfigParser()
|
||||||
|
config_dir = os.path.join(os.environ.get('XDG_CONFIG_HOME', os.path.expanduser('~/.config')), 'dpgpid')
|
||||||
|
log.debug("config_dir=%s" % config_dir)
|
||||||
|
self.config.read( [config_dir + '/dpgpid.conf'] )
|
||||||
|
|
||||||
|
def did_from_key(self):
|
||||||
|
log.debug("dpgpid.did_from_key()")
|
||||||
|
self.did = json.dumps({
|
||||||
|
"@context": "/ipfs/QmfS56jDfrXNaS6Xcsp3RJiXd2wyY7smeEAwyTAnL1RhEG",
|
||||||
|
"id": "did:ipid:" + self.key_id,
|
||||||
|
"created": self.key_created_at,
|
||||||
|
"publicKey": [{
|
||||||
|
"id": "did:ipid:" + self.key_id,
|
||||||
|
"type": "GpgVerificationKey2020",
|
||||||
|
"expires": self.key_expires_at,
|
||||||
|
"publicKeyGpg": self.key_public_key,
|
||||||
|
}, {
|
||||||
|
"id": "did:ipid:" + self.key_id,
|
||||||
|
"type": "JsonWebKey2020",
|
||||||
|
"expires": self.key_expires_at,
|
||||||
|
"publicKeyJwk": self.key_public_jwk,
|
||||||
|
}],
|
||||||
|
})
|
||||||
|
if self.key_updated_at:
|
||||||
|
self.did.update({"updated": self.key_updated_at,})
|
||||||
|
log.debug("dpgpid.did=%s" % self.did)
|
||||||
|
|
||||||
|
def do_list(self):
|
||||||
|
log.debug("dpgpid.do_list()")
|
||||||
|
gpgkeys = list(self.gpg.keylist(pattern=self.username, secret=True))
|
||||||
|
for gpgkey in gpgkeys:
|
||||||
|
self.key_from_gpg(gpgkey.fpr, self.password)
|
||||||
|
print("did:ipid:%s" % self.key_id)
|
||||||
|
self._cleanup()
|
||||||
|
|
||||||
|
def do_publish(self):
|
||||||
|
log.debug("dpgpid.do_publish()")
|
||||||
|
gpgkeys = list(self.gpg.keylist(pattern=self.username, secret=True))
|
||||||
|
if not gpgkeys:
|
||||||
|
log.warning(f"""Unable to find any key matching "{self.username}".""")
|
||||||
|
exit(1)
|
||||||
|
else:
|
||||||
|
gpgkey = gpgkeys[0]
|
||||||
|
log.info(f"""Found key id "{gpgkey.fpr}" matching "{self.username}".""")
|
||||||
|
self.key_from_gpg(gpgkey.fpr, self.password)
|
||||||
|
self.did_from_key()
|
||||||
|
self.did_cid = self.ipfs.add_json(self.did)
|
||||||
|
log.debug('dpgpid.did_cid=%s' % self.did_cid)
|
||||||
|
self.did_ipns = self.ipfs.name.publish(ipfs_path='/ipfs/' + self.did_cid, key=self.key_id)['Name']
|
||||||
|
log.debug('dpgpid.did_ipns=%s' % self.did_ipns)
|
||||||
|
self._cleanup()
|
||||||
|
|
||||||
|
def do_key(self):
|
||||||
|
log.debug("dpgpid.do_key()")
|
||||||
|
gpgkeys = list(self.gpg.keylist(pattern=self.username, secret=True))
|
||||||
|
if not gpgkeys:
|
||||||
|
log.warning(f"""Unable to find any key matching "{self.username}".""")
|
||||||
|
exit(1)
|
||||||
|
else:
|
||||||
|
gpgkey = gpgkeys[0]
|
||||||
|
log.info(f"""Found key id "{gpgkey.fpr}" matching "{self.username}".""")
|
||||||
|
self.key_from_gpg(gpgkey.fpr, self.password)
|
||||||
|
self.did_from_key()
|
||||||
|
self.did_cid = self.ipfs.add_json(self.did)
|
||||||
|
log.debug('dpgpid.did_cid=%s' % self.did_cid)
|
||||||
|
self.did_ipns = self.ipfs.name.publish(ipfs_path='/ipfs/' + self.did_cid, key=self.key_id)['Name']
|
||||||
|
log.debug('dpgpid.did_ipns=%s' % self.did_ipns)
|
||||||
|
didkit.keyToDID('key', self.key_secret_jwk)
|
||||||
|
self._cleanup()
|
||||||
|
|
||||||
|
def do_show(self):
|
||||||
|
log.debug("dpgpid.do_show()")
|
||||||
|
gpgkeys = list(self.gpg.keylist(pattern=self.username, secret=True))
|
||||||
|
if not gpgkeys:
|
||||||
|
log.warning(f"""Unable to find any key matching "{self.username}".""")
|
||||||
|
exit(1)
|
||||||
|
else:
|
||||||
|
gpgkey = gpgkeys[0]
|
||||||
|
log.info(f"""Found key id "{gpgkey.fpr}" matching "{self.username}".""")
|
||||||
|
self.key_from_gpg(gpgkey.fpr, self.password)
|
||||||
|
self.did_from_key()
|
||||||
|
print(self.did)
|
||||||
|
self._cleanup()
|
||||||
|
|
||||||
|
def ipfs_peerid(self, args):
|
||||||
|
log.debug("dpgpid.ipfs_peerid(%s)" % args)
|
||||||
|
try:
|
||||||
|
self.ipfs_peerid = self.ipfs.id()['ID']
|
||||||
|
except Exception as e:
|
||||||
|
log.error(f'Unable to get ipfs peer id: {e}')
|
||||||
|
exit()
|
||||||
|
log.debug('dpgpid.ipfs_peerid=%s' % self.ipfs_peerid)
|
||||||
|
|
||||||
|
def key_from_gpg(self, username, password):
|
||||||
|
log.debug("dpgpid.key_from_gpg(%s, %s)" % (username, password))
|
||||||
|
try:
|
||||||
|
key = keygen.keygen()
|
||||||
|
key.gpg = gpg.Context(armor=True, offline=True)
|
||||||
|
key.gpg.set_passphrase_cb(key.gpg_passphrase_cb)
|
||||||
|
key.username = username
|
||||||
|
key.password = password
|
||||||
|
key.ed25519_from_gpg()
|
||||||
|
key.pem_pkcs8_from_ed25519()
|
||||||
|
key.libp2p_from_ed25519()
|
||||||
|
key.b58mh_from_libp2p()
|
||||||
|
key.jwk_from_ed25519()
|
||||||
|
self.key_created_at = str(key.pgpy.created)
|
||||||
|
self.key_expires_at = str(key.pgpy.expires_at)
|
||||||
|
self.key_fingerprint = key.gpg_secret_key.fpr
|
||||||
|
self.key_id = key.ed25519_public_b58mh
|
||||||
|
self.key_is_expired = key.gpg_secret_key.expired
|
||||||
|
self.key_is_revoked = key.gpg_secret_key.revoked
|
||||||
|
self.key_public_key = str(key.pgpy.pubkey)
|
||||||
|
self.key_public_jwk = key.ed25519_public_jwk
|
||||||
|
self.key_secret_jwk = key.ed25519_secret_jwk
|
||||||
|
self.key_secret_pem = key.ed25519_secret_pem_pkcs8
|
||||||
|
self.key_signers = key.pgpy.signers
|
||||||
|
self.key_uids = key.gpg_secret_key.uids
|
||||||
|
self.key_updated_at = key.gpg_secret_key.last_update
|
||||||
|
log.debug("dpgpid.key.created_at=%s" % self.key_created_at)
|
||||||
|
log.debug("dpgpid.key.expires_at=%s" % self.key_expires_at)
|
||||||
|
log.debug("dpgpid.key.fingerprint=%s" % self.key_fingerprint)
|
||||||
|
log.debug("dpgpid.key.id=%s" % self.key_id)
|
||||||
|
log.debug("dpgpid.key.is_expired=%s" % self.key_is_expired)
|
||||||
|
log.debug("dpgpid.key.is_revoked=%s" % self.key_is_revoked)
|
||||||
|
log.debug("dpgpid.key.public_key=%s" % self.key_public_key)
|
||||||
|
log.debug("dpgpid.key.public_jwk=%s" % self.key_public_jwk)
|
||||||
|
log.debug("dpgpid.key.secret_jwk=%s" % self.key_secret_jwk)
|
||||||
|
log.debug("dpgpid.key.signers=%s" % self.key_signers)
|
||||||
|
log.debug("dpgpid.key.uids=%s" % self.key_uids)
|
||||||
|
log.debug("dpgpid.key.updated_at=%s" % self.key_updated_at)
|
||||||
|
except Exception as e:
|
||||||
|
log.error(f'Unable to get key from gpg: {e}')
|
||||||
|
exit(2)
|
||||||
|
|
||||||
|
def main(argv=None):
|
||||||
|
if argv is None:
|
||||||
|
argv = sys.argv[1:]
|
||||||
|
|
||||||
|
return dpgpid()._cli(argv)
|
||||||
|
|
||||||
|
def version(version=__version__):
|
||||||
|
print("%s v%s" % (sys.argv[0],version))
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
sys.exit(main())
|
||||||
|
|
245
dpgpid.py
245
dpgpid.py
|
@ -1,245 +0,0 @@
|
||||||
#!/usr/bin/env python3
|
|
||||||
# link: https://git.p2p.legal/aya/dpgpid/
|
|
||||||
# desc: generate did:ipid keys from gpg
|
|
||||||
|
|
||||||
# Copyleft 2022 Yann Autissier <aya@asycn.io>
|
|
||||||
|
|
||||||
# This program is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU Affero General Public License as published by
|
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU Affero General Public License for more details.
|
|
||||||
|
|
||||||
# You should have received a copy of the GNU Affero General Public License
|
|
||||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
import argparse
|
|
||||||
import configparser
|
|
||||||
import gpg
|
|
||||||
import ipfshttpclient
|
|
||||||
import json
|
|
||||||
import keygen
|
|
||||||
import logging as log
|
|
||||||
from SecureBytes import clearmem
|
|
||||||
import os
|
|
||||||
import re
|
|
||||||
import struct
|
|
||||||
import sys
|
|
||||||
import time
|
|
||||||
import warnings
|
|
||||||
|
|
||||||
__version__='0.0.1'
|
|
||||||
|
|
||||||
class dpgpid:
|
|
||||||
def __init__(self):
|
|
||||||
self.parser = argparse.ArgumentParser(description="""
|
|
||||||
Generate did:ipid keys from gpg.
|
|
||||||
It converts a gpg key to a Decentralized IDentifier.""")
|
|
||||||
self.parser.add_argument(
|
|
||||||
"-d",
|
|
||||||
"--debug",
|
|
||||||
action="store_true",
|
|
||||||
help="show debug informations",
|
|
||||||
)
|
|
||||||
self.parser.add_argument(
|
|
||||||
"-q",
|
|
||||||
"--quiet",
|
|
||||||
action="store_true",
|
|
||||||
help="show only errors",
|
|
||||||
)
|
|
||||||
self.parser.add_argument(
|
|
||||||
"-t",
|
|
||||||
"--type",
|
|
||||||
choices=['list','show','publish','base64','duniter','ipfs','jwk'],
|
|
||||||
default="list",
|
|
||||||
dest="type",
|
|
||||||
help="output text format, default: base58",
|
|
||||||
)
|
|
||||||
self.parser.add_argument(
|
|
||||||
"-v",
|
|
||||||
"--verbose",
|
|
||||||
action="store_true",
|
|
||||||
help="show more informations",
|
|
||||||
)
|
|
||||||
self.parser.add_argument(
|
|
||||||
"--version",
|
|
||||||
action="store_true",
|
|
||||||
help="show version and exit",
|
|
||||||
)
|
|
||||||
self.parser.add_argument(
|
|
||||||
'username',
|
|
||||||
nargs="?",
|
|
||||||
)
|
|
||||||
self.parser.add_argument(
|
|
||||||
'password',
|
|
||||||
nargs="?",
|
|
||||||
)
|
|
||||||
|
|
||||||
def _check_args(self, args):
|
|
||||||
log.debug("dpgpid._check_args(%s)" % args)
|
|
||||||
if False:
|
|
||||||
self.parser.error('dpgpid requires an input file or a username')
|
|
||||||
|
|
||||||
def _cleanup(self):
|
|
||||||
log.debug("dpgpid._cleanup()")
|
|
||||||
self.ipfs.close()
|
|
||||||
|
|
||||||
def _invalid_type(self):
|
|
||||||
log.debug("dpgpid._invalid_type()")
|
|
||||||
self.parser.error(f"type {self.type} is not valid.")
|
|
||||||
|
|
||||||
def _load_config(self):
|
|
||||||
log.debug("dpgpid._load_config()")
|
|
||||||
self.config = configparser.RawConfigParser()
|
|
||||||
config_dir = os.path.join(os.environ.get('XDG_CONFIG_HOME', os.path.expanduser('~/.config')), 'dpgpid')
|
|
||||||
log.debug("config_dir=%s" % config_dir)
|
|
||||||
self.config.read( [config_dir + '/dpgpid.conf'] )
|
|
||||||
|
|
||||||
def _run(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)
|
|
||||||
|
|
||||||
self._check_args(args)
|
|
||||||
self._load_config()
|
|
||||||
self.gpg = gpg.Context(armor=True, offline=True)
|
|
||||||
self.ipfs = ipfshttpclient.connect('/ip4/172.18.0.2/tcp/5001/',session=True)
|
|
||||||
method = getattr(self, f'do_{self.type}', self._invalid_type)
|
|
||||||
return method()
|
|
||||||
|
|
||||||
def did_from_key(self):
|
|
||||||
log.debug("dpgpid.did_from_key()")
|
|
||||||
self.did = json.dumps({
|
|
||||||
"@context": "/ipfs/QmfS56jDfrXNaS6Xcsp3RJiXd2wyY7smeEAwyTAnL1RhEG",
|
|
||||||
"id": "did:ipid:" + self.key_id,
|
|
||||||
"created": self.key_created_at,
|
|
||||||
"publicKey": [{
|
|
||||||
"id": "did:ipid:" + self.key_id,
|
|
||||||
"type": "GpgVerificationKey2020",
|
|
||||||
"expires": self.key_expires_at,
|
|
||||||
"publicKeyGpg": self.key_public_key,
|
|
||||||
}, {
|
|
||||||
"id": "did:ipid:" + self.key_id,
|
|
||||||
"type": "JsonWebKey2020",
|
|
||||||
"expires": self.key_expires_at,
|
|
||||||
"publicKeyJwk": self.key_public_jwk,
|
|
||||||
}],
|
|
||||||
})
|
|
||||||
if self.key_updated_at:
|
|
||||||
self.did.update({"updated": self.key_updated_at,})
|
|
||||||
log.debug("dpgpid.did=%s" % self.did)
|
|
||||||
|
|
||||||
def do_list(self):
|
|
||||||
log.debug("dpgpid.do_list()")
|
|
||||||
gpgkeys = list(self.gpg.keylist(pattern=self.username, secret=True))
|
|
||||||
for gpgkey in gpgkeys:
|
|
||||||
self.key_from_gpg(gpgkey.fpr, self.password)
|
|
||||||
print("did:ipid:%s" % self.key_id)
|
|
||||||
self._cleanup()
|
|
||||||
|
|
||||||
def do_publish(self):
|
|
||||||
log.debug("dpgpid.do_publish()")
|
|
||||||
gpgkeys = list(self.gpg.keylist(pattern=self.username, secret=True))
|
|
||||||
if not gpgkeys:
|
|
||||||
log.warning(f"""Unable to find any key matching "{self.username}".""")
|
|
||||||
exit(1)
|
|
||||||
else:
|
|
||||||
gpgkey = gpgkeys[0]
|
|
||||||
log.info(f"""Found key id "{gpgkey.fpr}" matching "{self.username}".""")
|
|
||||||
self.key_from_gpg(gpgkey.fpr, self.password)
|
|
||||||
self.did_from_key()
|
|
||||||
self.did_cid = self.ipfs.add_json(self.did)
|
|
||||||
log.debug('dpgpid.did_cid=%s' % self.did_cid)
|
|
||||||
self.did_ipns = self.ipfs.name.publish(ipfs_path='/ipfs/' + self.did_cid, key=self.key_id)['Name']
|
|
||||||
log.debug('dpgpid.did_ipns=%s' % self.did_ipns)
|
|
||||||
self._cleanup()
|
|
||||||
|
|
||||||
def do_show(self):
|
|
||||||
log.debug("dpgpid.do_show()")
|
|
||||||
gpgkeys = list(self.gpg.keylist(pattern=self.username, secret=True))
|
|
||||||
if not gpgkeys:
|
|
||||||
log.warning(f"""Unable to find any key matching "{self.username}".""")
|
|
||||||
exit(1)
|
|
||||||
else:
|
|
||||||
gpgkey = gpgkeys[0]
|
|
||||||
log.info(f"""Found key id "{gpgkey.fpr}" matching "{self.username}".""")
|
|
||||||
self.key_from_gpg(gpgkey.fpr, self.password)
|
|
||||||
self.did_from_key()
|
|
||||||
print(self.did)
|
|
||||||
self._cleanup()
|
|
||||||
|
|
||||||
def key_from_gpg(self, username, password):
|
|
||||||
log.debug("dpgpid.key_from_gpg(%s, %s)" % (username, password))
|
|
||||||
try:
|
|
||||||
key = keygen.keygen()
|
|
||||||
key.gpg = gpg.Context(armor=True, offline=True)
|
|
||||||
key.gpg.set_passphrase_cb(key.gpg_passphrase_cb)
|
|
||||||
key.username = username
|
|
||||||
key.password = password
|
|
||||||
key.ed25519_from_gpg()
|
|
||||||
key.pem_pkcs8_from_ed25519()
|
|
||||||
key.protobuf_from_ed25519()
|
|
||||||
key.b58mh_from_protobuf()
|
|
||||||
key.jwk_from_ed25519()
|
|
||||||
self.key_created_at = str(key.pgpy.created)
|
|
||||||
self.key_expires_at = str(key.pgpy.expires_at)
|
|
||||||
self.key_fingerprint = key.gpg_secret_key.fpr
|
|
||||||
self.key_id = key.ed25519_public_b58mh
|
|
||||||
self.key_is_expired = key.gpg_secret_key.expired
|
|
||||||
self.key_is_revoked = key.gpg_secret_key.revoked
|
|
||||||
self.key_public_key = str(key.pgpy.pubkey)
|
|
||||||
self.key_public_jwk = key.ed25519_public_jwk
|
|
||||||
self.key_secret_jwk = key.ed25519_secret_jwk
|
|
||||||
self.key_secret_pem = key.ed25519_secret_pem_pkcs8
|
|
||||||
self.key_signers = key.pgpy.signers
|
|
||||||
self.key_uids = key.gpg_secret_key.uids
|
|
||||||
self.key_updated_at = key.gpg_secret_key.last_update
|
|
||||||
log.debug("dpgpid.key.created_at=%s" % self.key_created_at)
|
|
||||||
log.debug("dpgpid.key.expires_at=%s" % self.key_expires_at)
|
|
||||||
log.debug("dpgpid.key.fingerprint=%s" % self.key_fingerprint)
|
|
||||||
log.debug("dpgpid.key.id=%s" % self.key_id)
|
|
||||||
log.debug("dpgpid.key.is_expired=%s" % self.key_is_expired)
|
|
||||||
log.debug("dpgpid.key.is_revoked=%s" % self.key_is_revoked)
|
|
||||||
log.debug("dpgpid.key.public_key=%s" % self.key_public_key)
|
|
||||||
log.debug("dpgpid.key.public_jwk=%s" % self.key_public_jwk)
|
|
||||||
log.debug("dpgpid.key.secret_jwk=%s" % self.key_secret_jwk)
|
|
||||||
log.debug("dpgpid.key.signers=%s" % self.key_signers)
|
|
||||||
log.debug("dpgpid.key.uids=%s" % self.key_uids)
|
|
||||||
log.debug("dpgpid.key.updated_at=%s" % self.key_updated_at)
|
|
||||||
except Exception as e:
|
|
||||||
log.error(f'Unable to get key from gpg: {e}')
|
|
||||||
exit(2)
|
|
||||||
|
|
||||||
def main(argv=None):
|
|
||||||
if argv is None:
|
|
||||||
argv = sys.argv[1:]
|
|
||||||
|
|
||||||
cli = dpgpid()
|
|
||||||
return cli._run(argv)
|
|
||||||
|
|
||||||
def version(version=__version__):
|
|
||||||
print("%s v%s" % (sys.argv[0],version))
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
sys.exit(main())
|
|
|
@ -0,0 +1,496 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
# link: https://git.p2p.legal/aya/dpgpid/
|
||||||
|
# desc: dpgpid builds a decentralized gpg world of trust with did over ipfs
|
||||||
|
|
||||||
|
# Copyleft 2022 Yann Autissier <aya@asycn.io>
|
||||||
|
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU Affero General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU Affero General Public License for more details.
|
||||||
|
|
||||||
|
# You should have received a copy of the GNU Affero General Public License
|
||||||
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
from cryptography.hazmat.primitives import serialization
|
||||||
|
from jwcrypto.jwk import JWK
|
||||||
|
import base36
|
||||||
|
import base58
|
||||||
|
import base64
|
||||||
|
import duniterpy.key
|
||||||
|
import gpg
|
||||||
|
import logging as log
|
||||||
|
import pgpy
|
||||||
|
import pynentry
|
||||||
|
import re
|
||||||
|
import warnings
|
||||||
|
|
||||||
|
def from_args(args, config):
|
||||||
|
log.debug("key.from_args(%s, %s)" % (args, config))
|
||||||
|
from key import ed25519
|
||||||
|
if args.gpg:
|
||||||
|
return from_gpg()
|
||||||
|
else:
|
||||||
|
scrypt_params = duniterpy.key.scrypt_params.ScryptParams(
|
||||||
|
int(config.get('scrypt', 'n')) if config and config.has_option('scrypt', 'n') else 4096,
|
||||||
|
int(config.get('scrypt', 'r')) if config and config.has_option('scrypt', 'r') else 16,
|
||||||
|
int(config.get('scrypt', 'p')) if config and config.has_option('scrypt', 'p') else 1,
|
||||||
|
int(config.get('scrypt', 'sl')) if config and config.has_option('scrypt', 'sl') else 32,
|
||||||
|
)
|
||||||
|
if args.input:
|
||||||
|
return from_file(args.input, args.password, scrypt_params)
|
||||||
|
else:
|
||||||
|
if args.mnemonic:
|
||||||
|
return from_mnemonic(' '.join(args.username), scrypt_params)
|
||||||
|
else:
|
||||||
|
return from_credentials(args.username[0], args.password, scrypt_params)
|
||||||
|
|
||||||
|
def from_credentials(username, password=None, scrypt_params=None):
|
||||||
|
log.debug("key.from_credentials(%s, %s, %s)" % (username, password, scrypt_params))
|
||||||
|
try:
|
||||||
|
if not password:
|
||||||
|
with pynentry.PynEntry() as p:
|
||||||
|
p.description = f"""Please enter the passord for username "{username}"."""
|
||||||
|
p.prompt = 'Passsord:'
|
||||||
|
try:
|
||||||
|
password = p.get_pin()
|
||||||
|
except pynentry.PinEntryCancelled:
|
||||||
|
log.warning('Cancelled! Goodbye.')
|
||||||
|
exit(1)
|
||||||
|
return from_duniterpy(duniterpy.key.SigningKey.from_credentials(
|
||||||
|
username,
|
||||||
|
password,
|
||||||
|
scrypt_params
|
||||||
|
))
|
||||||
|
except Exception as e:
|
||||||
|
log.error(f'Unable to get key from credentials: {e}')
|
||||||
|
exit(2)
|
||||||
|
|
||||||
|
def from_duniterpy(duniterpy):
|
||||||
|
log.debug("key.from_duniterpy(%s)" % duniterpy)
|
||||||
|
return ed25519.from_duniterpy(duniterpy)
|
||||||
|
|
||||||
|
def from_file(input_file, password=None, scrypt_params=None):
|
||||||
|
log.debug("key.from_file()")
|
||||||
|
try:
|
||||||
|
with open(input_file, 'r') as file:
|
||||||
|
lines = file.readlines()
|
||||||
|
if len(lines) > 0:
|
||||||
|
line = lines[0].strip()
|
||||||
|
regex_ewif = re.compile('^Type: EWIF$')
|
||||||
|
regex_jwk = re.compile('^\\s*{\\s*"crv":\\s*"Ed25519",\\s*"d":\\s*"(.)+",\\s*"kty":\\s*"OKP",\\s*"x":\\s*"(.)+"\\s*}')
|
||||||
|
regex_nacl = re.compile('^\\s*{\\s*"priv":\\s*"[0-9a-fA-F]+",\\s*"verify":\\s*"[0-9a-fA-F]+",\\s*"sign":\\s*"[0-9a-fA-F]+"\\s*}')
|
||||||
|
regex_pem = re.compile('^-----BEGIN PRIVATE KEY-----$')
|
||||||
|
regex_pubsec = re.compile('^Type: PubSec$')
|
||||||
|
regex_seed = re.compile('^[0-9a-fA-F]{64}$')
|
||||||
|
regex_ssb = re.compile('\\s*{\\s*"curve":\\s*"ed25519",\\s*"public":\\s*"(.+)\\.ed25519",\\s*"private":\\s*"(.+)\\.ed25519",\\s*"id":\\s*"@(.+).ed25519"\\s*}')
|
||||||
|
regex_wif = re.compile('^Type: WIF$')
|
||||||
|
if re.search(regex_ewif, line):
|
||||||
|
log.info("input file format detected: ewif")
|
||||||
|
if not password:
|
||||||
|
with pynentry.PynEntry() as p:
|
||||||
|
p.description = f"""Data in EWIF file is encrypted.
|
||||||
|
Please enter a password to decrypt seed.
|
||||||
|
"""
|
||||||
|
p.prompt = 'Passphrase:'
|
||||||
|
try:
|
||||||
|
password = p.get_pin()
|
||||||
|
except pynentry.PinEntryCancelled:
|
||||||
|
log.warning('Cancelled! Goodbye.')
|
||||||
|
exit(1)
|
||||||
|
return from_duniterpy(duniterpy.key.SigningKey.from_ewif_file(input_file, password))
|
||||||
|
elif re.search(regex_jwk, line):
|
||||||
|
log.info("input file format detected: jwk")
|
||||||
|
return from_jwk(JWK.from_json(line))
|
||||||
|
elif re.search(regex_nacl, line):
|
||||||
|
log.info("input file format detected: nacl")
|
||||||
|
return from_duniterpy(duniterpy.key.SigningKey.from_private_key(input_file))
|
||||||
|
elif re.search(regex_pem, line):
|
||||||
|
log.info("input file format detected: pem")
|
||||||
|
return from_pem(''.join(lines).encode())
|
||||||
|
elif re.search(regex_pubsec, line):
|
||||||
|
log.info("input file format detected: pubsec")
|
||||||
|
return from_duniterpy(duniterpy.key.SigningKey.from_pubsec_file(input_file))
|
||||||
|
elif re.search(regex_seed, line):
|
||||||
|
log.info("input file format detected: seed")
|
||||||
|
return from_duniterpy(duniterpy.key.SigningKey.from_seedhex_file(input_file))
|
||||||
|
elif re.search(regex_ssb, line):
|
||||||
|
log.info("input file format detected: ssb")
|
||||||
|
return from_duniterpy(duniterpy.key.SigningKey.from_ssb_file(input_file))
|
||||||
|
elif re.search(regex_wif, line):
|
||||||
|
log.info("input file format detected: wif")
|
||||||
|
return from_duniterpy(duniterpy.key.SigningKey.from_wif_file(input_file))
|
||||||
|
elif len(line.split(' ')) == 12:
|
||||||
|
log.info("input file format detected: mnemonic")
|
||||||
|
return from_mnemonic(line, scrypt_params)
|
||||||
|
elif len(lines) > 1:
|
||||||
|
log.info("input file format detected: credentials")
|
||||||
|
return from_credentials(line, lines[1].strip(), scrypt_params)
|
||||||
|
else:
|
||||||
|
raise NotImplementedError('unknown input file format.')
|
||||||
|
else:
|
||||||
|
raise NotImplementedError('empty file.')
|
||||||
|
except UnicodeDecodeError as e:
|
||||||
|
try:
|
||||||
|
with open(input_file, 'rb') as file:
|
||||||
|
lines = file.readlines()
|
||||||
|
if len(lines) > 0:
|
||||||
|
line = lines[0].strip()
|
||||||
|
regex_dewif = re.compile(b'^\x00\x00\x00\x01\x00\x00\x00\x01')
|
||||||
|
regex_p2p = re.compile(b'^\x08\x01\x12@')
|
||||||
|
if re.search(regex_dewif, line):
|
||||||
|
log.info("input file format detected: dewif")
|
||||||
|
if not password:
|
||||||
|
with pynentry.PynEntry() as p:
|
||||||
|
p.description = f"""Data in DEWIF file is encrypted.
|
||||||
|
Please enter a password to decrypt seed.
|
||||||
|
"""
|
||||||
|
p.prompt = 'Passphrase:'
|
||||||
|
try:
|
||||||
|
password = p.get_pin()
|
||||||
|
except pynentry.PinEntryCancelled:
|
||||||
|
log.warning('Cancelled! Goodbye.')
|
||||||
|
exit(1)
|
||||||
|
return from_duniterpy(duniterpy.key.SigningKey.from_dewif_file(input_file, password))
|
||||||
|
if re.search(regex_p2p, line):
|
||||||
|
log.info("input file format detected: p2p")
|
||||||
|
return from_libp2p(line)
|
||||||
|
else:
|
||||||
|
raise NotImplementedError('unknown input file format.')
|
||||||
|
else:
|
||||||
|
raise NotImplementedError('empty file.')
|
||||||
|
except Exception as e:
|
||||||
|
log.error(f'Unable to get key from file {input_file}: {e}')
|
||||||
|
exit(2)
|
||||||
|
except Exception as e:
|
||||||
|
log.error(f'Unable to get key from file {input_file}: {e}')
|
||||||
|
exit(2)
|
||||||
|
|
||||||
|
def from_gpg():
|
||||||
|
log.debug("key.from_gpg()")
|
||||||
|
try:
|
||||||
|
self.pgpy()
|
||||||
|
return self.from_pgpy()
|
||||||
|
except Exception as e:
|
||||||
|
log.error(f'Unable to get key from gpg: {e}')
|
||||||
|
exit(2)
|
||||||
|
|
||||||
|
def from_jwk(jwk):
|
||||||
|
log.debug("key.from_jwk(%s)" % jwk)
|
||||||
|
return ed25519.from_jwk(jwk)
|
||||||
|
|
||||||
|
def from_libp2p(libp2p):
|
||||||
|
log.debug("key.from_libp2p(%s)" % libp2p)
|
||||||
|
return ed25519.from_libp2p(libp2p)
|
||||||
|
|
||||||
|
def from_mnemonic(mnemonic, scrypt_params=None):
|
||||||
|
log.debug("key.from_mnemonic(%s, %s)" % (mnemonic, scrypt_params))
|
||||||
|
try:
|
||||||
|
return from_duniterpy(duniterpy.key.SigningKey.from_dubp_mnemonic(
|
||||||
|
mnemonic,
|
||||||
|
scrypt_params
|
||||||
|
))
|
||||||
|
except Exception as e:
|
||||||
|
log.error(f'Unable to get key from mnemonic: {e}')
|
||||||
|
exit(2)
|
||||||
|
|
||||||
|
def from_pem(pem):
|
||||||
|
log.debug("key.from_pem(%s)" % pem)
|
||||||
|
return ed25519.from_pem(pem)
|
||||||
|
|
||||||
|
def from_pgpy(self, pgpy, password):
|
||||||
|
log.debug("key.from_pgpy(%s)" % pgpy)
|
||||||
|
try:
|
||||||
|
log.debug("key.pgpy.fingerprint.keyid=%s" % pgpy.fingerprint.keyid)
|
||||||
|
log.debug("key.pgpy.is_protected=%s" % pgpy.is_protected)
|
||||||
|
if pgpy.is_protected:
|
||||||
|
if not password:
|
||||||
|
with pynentry.PynEntry() as p:
|
||||||
|
p.description = f"""The exported pgp key id "{pgpy.fingerprint.keyid}" is password protected.
|
||||||
|
Please enter the passphrase again to unlock it.
|
||||||
|
"""
|
||||||
|
p.prompt = 'Passphrase:'
|
||||||
|
try:
|
||||||
|
password = p.get_pin()
|
||||||
|
except pynentry.PinEntryCancelled:
|
||||||
|
log.warning('Cancelled! Goodbye.')
|
||||||
|
exit(1)
|
||||||
|
try:
|
||||||
|
with warnings.catch_warnings():
|
||||||
|
# remove CryptographyDeprecationWarning about deprecated
|
||||||
|
# SymmetricKeyAlgorithm IDEA, CAST5 and Blowfish (PGPy v0.5.4)
|
||||||
|
warnings.simplefilter('ignore')
|
||||||
|
with pgpy.unlock(password):
|
||||||
|
assert pgpy.is_unlocked
|
||||||
|
log.debug("ed25519.pgpy.is_unlocked=%s" % pgpy.is_unlocked)
|
||||||
|
seed = self.ed25519_seed_bytes_from_pgpy()
|
||||||
|
except Exception as e:
|
||||||
|
log.error(f"""Unable to unlock pgp secret key id "{self.pgpy.fingerprint.keyid}" of user "{self.username}": {e}""")
|
||||||
|
exit(2)
|
||||||
|
else:
|
||||||
|
seed = self.ed25519_seed_bytes_from_pgpy()
|
||||||
|
self.ed25519_from_seed_bytes()
|
||||||
|
except Exception as e:
|
||||||
|
log.error(f'Unable to get ed25519 seed bytes from pgpy: {e}')
|
||||||
|
exit(2)
|
||||||
|
|
||||||
|
class key():
|
||||||
|
def __init__(self):
|
||||||
|
self.algorithm = 'undef'
|
||||||
|
self.gpg = gpg.Context(armor=True, offline=True)
|
||||||
|
self.gpg.set_passphrase_cb(self.gpg_passphrase_cb)
|
||||||
|
|
||||||
|
def __del__(self):
|
||||||
|
self._cleanup()
|
||||||
|
|
||||||
|
def _cleanup(self):
|
||||||
|
log.debug("key._cleanup()")
|
||||||
|
raise NotImplementedError(f"_cleanup() is not implemented for algorithm {self.algorithm}")
|
||||||
|
|
||||||
|
def gpg_passphrase_cb(self, uid_hint, passphrase_info, prev_was_bad):
|
||||||
|
log.debug("key.gpg_passphrase_cb(%s, %s, %s)" % (uid_hint, passphrase_info, prev_was_bad))
|
||||||
|
return self.password
|
||||||
|
|
||||||
|
def to_b36mf(self):
|
||||||
|
log.debug("key.to_b36mf()")
|
||||||
|
if not hasattr(self, 'public_cidv1') or not hasattr(self, 'secret_cidv1'):
|
||||||
|
self.to_cidv1()
|
||||||
|
try:
|
||||||
|
self.public_b36mf = 'k' + base36.dumps(int.from_bytes(self.public_cidv1, byteorder='big'))
|
||||||
|
self.secret_b36mf = 'k' + base36.dumps(int.from_bytes(self.secret_cidv1, byteorder='big'))
|
||||||
|
except Exception as e:
|
||||||
|
log.error(f'Unable to get b36mf from cidv1: {e}')
|
||||||
|
exit(2)
|
||||||
|
log.debug("key.public_b36mf=%s" % self.public_b36mf)
|
||||||
|
log.debug("key.secret_b36mf=%s" % self.secret_b36mf)
|
||||||
|
|
||||||
|
def to_b58mf(self):
|
||||||
|
log.debug("key.to_b58mf()")
|
||||||
|
if not hasattr(self, 'public_cidv1') or not hasattr(self, 'secret_cidv1'):
|
||||||
|
self.to_cidv1()
|
||||||
|
try:
|
||||||
|
self.public_b58mf = 'z' + base58.b58encode(self.public_cidv1).decode('ascii')
|
||||||
|
self.secret_b58mf = 'z' + base58.b58encode(self.secret_cidv1).decode('ascii')
|
||||||
|
except Exception as e:
|
||||||
|
log.error(f'Unable to get b58mf from cidv1: {e}')
|
||||||
|
exit(2)
|
||||||
|
log.debug("key.public_b58mf=%s" % self.public_b58mf)
|
||||||
|
log.debug("key.secret_b58mf=%s" % self.secret_b58mf)
|
||||||
|
|
||||||
|
def to_b58mh(self):
|
||||||
|
log.debug("key.to_b58mh()")
|
||||||
|
if not hasattr(self, 'public_libp2p') or not hasattr(self, 'secret_libp2p'):
|
||||||
|
self.to_libp2p()
|
||||||
|
try:
|
||||||
|
self.public_b58mh = base58.b58encode(self.public_libp2p).decode('ascii')
|
||||||
|
self.secret_b58mh = base58.b58encode(self.secret_libp2p).decode('ascii')
|
||||||
|
except Exception as e:
|
||||||
|
log.error(f'Unable to get b58mh from libp2p: {e}')
|
||||||
|
exit(2)
|
||||||
|
log.debug("key.public_b58mh=%s" % self.public_b58mh)
|
||||||
|
log.debug("key.secret_b58mh=%s" % self.secret_b58mh)
|
||||||
|
|
||||||
|
def to_b64mh(self):
|
||||||
|
log.debug("key.to_b64mh()")
|
||||||
|
if not hasattr(self, 'public_libp2p') or not hasattr(self, 'secret_libp2p'):
|
||||||
|
self.to_libp2p()
|
||||||
|
try:
|
||||||
|
self.public_b64mh = base64.b64encode(self.public_libp2p).decode('ascii')
|
||||||
|
self.secret_b64mh = base64.b64encode(self.secret_libp2p).decode('ascii')
|
||||||
|
except Exception as e:
|
||||||
|
log.error(f'Unable to get b64mh from libp2p: {e}')
|
||||||
|
exit(2)
|
||||||
|
log.debug("key.public_b64mh=%s" % self.public_b64mh)
|
||||||
|
log.debug("key.secret_b64mh=%s" % self.secret_b64mh)
|
||||||
|
|
||||||
|
def to_base58(self):
|
||||||
|
log.debug("key.to_base58()")
|
||||||
|
try:
|
||||||
|
self.public_base58 = base58.b58encode(self.public_bytes).decode('ascii')
|
||||||
|
self.secret_base58 = base58.b58encode(self.secret_bytes).decode('ascii')
|
||||||
|
except Exception as e:
|
||||||
|
log.error(f'Unable to get base58: {e}')
|
||||||
|
exit(2)
|
||||||
|
log.debug("key.public_base58=%s" % self.public_base58)
|
||||||
|
log.debug("key.secret_base58=%s" % self.secret_base58)
|
||||||
|
|
||||||
|
def to_base64(self):
|
||||||
|
log.debug("key.to_base64()")
|
||||||
|
try:
|
||||||
|
self.public_base64 = base64.b64encode(self.public_bytes).decode('ascii')
|
||||||
|
self.secret_base64 = base64.b64encode(self.secret_bytes).decode('ascii')
|
||||||
|
except Exception as e:
|
||||||
|
log.error(f'Unable to get base64: {e}')
|
||||||
|
exit(2)
|
||||||
|
log.debug("key.public_base64=%s" % self.public_base64)
|
||||||
|
log.debug("key.secret_base64=%s" % self.secret_base64)
|
||||||
|
|
||||||
|
def to_cidv1(self):
|
||||||
|
log.debug("key.to_cidv1()")
|
||||||
|
if not hasattr(self, 'public_libp2p') or not hasattr(self, 'secret_libp2p'):
|
||||||
|
self.to_libp2p()
|
||||||
|
try:
|
||||||
|
# \x01: multicodec cid prefix = CIDv1
|
||||||
|
# \x72: multicodec content prefix = libp2p-key
|
||||||
|
self.public_cidv1 = b'\x01\x72' + self.public_libp2p
|
||||||
|
self.secret_cidv1 = b'\x01\x72' + self.secret_libp2p
|
||||||
|
except Exception as e:
|
||||||
|
log.error(f'Unable to get cidv1: {e}')
|
||||||
|
exit(2)
|
||||||
|
log.debug("key.public_cidv1=%s" % self.public_cidv1)
|
||||||
|
log.debug("key.secret_cidv1=%s" % self.secret_cidv1)
|
||||||
|
|
||||||
|
def to_duniterpy(self):
|
||||||
|
log.debug("key.to_duniterpy()")
|
||||||
|
raise NotImplementedError(f"to_duniterpy() is not implemented for algorithm {self.algorithm}")
|
||||||
|
|
||||||
|
def to_file(self, output_file, file_format=None, password=None):
|
||||||
|
log.debug("key().to_file(%s, %s, %s)" % (output_file, file_format, password))
|
||||||
|
try:
|
||||||
|
if file_format == 'dewif':
|
||||||
|
if not hasattr(self, 'duniterpy'):
|
||||||
|
self.to_duniterpy()
|
||||||
|
if not password:
|
||||||
|
with pynentry.PynEntry() as p:
|
||||||
|
p.description = f"""Data in DEWIF file needs to be encrypted.
|
||||||
|
Please enter a password to encrypt seed.
|
||||||
|
"""
|
||||||
|
p.prompt = 'Passphrase:'
|
||||||
|
try:
|
||||||
|
password = p.get_pin()
|
||||||
|
except pynentry.PinEntryCancelled:
|
||||||
|
log.warning('Cancelled! Goodbye.')
|
||||||
|
exit(1)
|
||||||
|
self.duniterpy.save_dewif_v1_file(output_file, password)
|
||||||
|
elif file_format == 'ewif':
|
||||||
|
if not hasattr(self, 'duniterpy'):
|
||||||
|
self.to_duniterpy()
|
||||||
|
if not password:
|
||||||
|
with pynentry.PynEntry() as p:
|
||||||
|
p.description = f"""Data in EWIF file needs to be encrypted.
|
||||||
|
Please enter a password to encrypt seed.
|
||||||
|
"""
|
||||||
|
p.prompt = 'Passphrase:'
|
||||||
|
try:
|
||||||
|
password = p.get_pin()
|
||||||
|
except pynentry.PinEntryCancelled:
|
||||||
|
log.warning('Cancelled! Goodbye.')
|
||||||
|
exit(1)
|
||||||
|
self.duniterpy.save_ewif_file(output_file, password)
|
||||||
|
elif file_format == 'jwk':
|
||||||
|
if not hasattr(self, 'jwk'):
|
||||||
|
self.to_jwk()
|
||||||
|
with open(output_file, "w") as file:
|
||||||
|
file.write(self.jwk.export())
|
||||||
|
elif file_format == 'nacl':
|
||||||
|
if not hasattr(self, 'duniterpy'):
|
||||||
|
self.to_duniterpy()
|
||||||
|
self.duniterpy.save_private_key(output_file)
|
||||||
|
elif file_format == 'p2p':
|
||||||
|
if not hasattr(self, 'secret_libp2p'):
|
||||||
|
self.to_libp2p()
|
||||||
|
with open(output_file, "wb") as file:
|
||||||
|
file.write(self.secret_libp2p)
|
||||||
|
elif file_format == 'pubsec':
|
||||||
|
if not hasattr(self, 'duniterpy'):
|
||||||
|
self.to_duniterpy()
|
||||||
|
self.duniterpy.save_pubsec_file(output_file)
|
||||||
|
elif file_format == 'seed':
|
||||||
|
if not hasattr(self, 'duniterpy'):
|
||||||
|
self.to_duniterpy()
|
||||||
|
self.duniterpy.save_seedhex_file(output_file)
|
||||||
|
elif file_format == 'wif':
|
||||||
|
if not hasattr(self, 'duniterpy'):
|
||||||
|
self.to_duniterpy()
|
||||||
|
self.duniterpy.save_wif_file(output_file)
|
||||||
|
else:
|
||||||
|
if not hasattr(self, 'secret_pem_pkcs8'):
|
||||||
|
self.to_pem_pkcs8()
|
||||||
|
with open(output_file, "w") as file:
|
||||||
|
file.write(self.secret_pem_pkcs8)
|
||||||
|
except Exception as e:
|
||||||
|
log.error(f'Unable to write key to output file {output_file}: {e}')
|
||||||
|
exit(2)
|
||||||
|
|
||||||
|
def to_jwk(self):
|
||||||
|
log.debug("key.to_jwk()")
|
||||||
|
try:
|
||||||
|
if not hasattr(self, 'jwk'):
|
||||||
|
self.jwk = JWK.from_pyca(self.cryptography)
|
||||||
|
self.public_jwk = self.jwk.export_public()
|
||||||
|
self.secret_jwk = self.jwk.export_private()
|
||||||
|
except Exception as e:
|
||||||
|
log.error(f'Unable to get jwk: {e}')
|
||||||
|
exit(2)
|
||||||
|
|
||||||
|
def to_libp2p(self):
|
||||||
|
log.debug("key.to_libp2p()")
|
||||||
|
try:
|
||||||
|
if not hasattr(self, 'public_proto2') or not hasattr(self, 'secret_proto2'):
|
||||||
|
self.to_proto2()
|
||||||
|
# \x00: multihash prefix = raw id
|
||||||
|
# \x24: multihash length = 36 bytes
|
||||||
|
self.public_libp2p = b'\x00$' + self.public_proto2
|
||||||
|
self.secret_libp2p = self.secret_proto2
|
||||||
|
except Exception as e:
|
||||||
|
log.error(f'Unable to get libp2p: {e}')
|
||||||
|
exit(2)
|
||||||
|
log.debug("key.public_libp2p=%s" % self.public_libp2p)
|
||||||
|
log.debug("key.secret_libp2p=%s" % self.secret_libp2p)
|
||||||
|
|
||||||
|
def to_pem_pkcs8(self):
|
||||||
|
log.debug("key.to_pem_pkcs8()")
|
||||||
|
try:
|
||||||
|
self.secret_pem_pkcs8 = self.cryptography.private_bytes(
|
||||||
|
encoding=serialization.Encoding.PEM,
|
||||||
|
format=serialization.PrivateFormat.PKCS8,
|
||||||
|
encryption_algorithm=serialization.NoEncryption()
|
||||||
|
).decode('ascii')
|
||||||
|
except Exception as e:
|
||||||
|
log.error(f'Unable to get pem pkcs8: {e}')
|
||||||
|
exit(2)
|
||||||
|
log.debug("key.secret_pem_pkcs8=%s" % self.secret_pem_pkcs8)
|
||||||
|
|
||||||
|
def to_pgpy(self):
|
||||||
|
log.debug("key.to_pgpy()")
|
||||||
|
try:
|
||||||
|
self.gpg_secret_keys = list(self.gpg.keylist(pattern=self.username, secret=True))
|
||||||
|
log.debug("key.gpg_secret_keys=%s" % self.gpg_secret_keys)
|
||||||
|
if not self.gpg_secret_keys:
|
||||||
|
log.warning(f"""Unable to find any key matching "{self.username}".""")
|
||||||
|
exit(1)
|
||||||
|
else:
|
||||||
|
self.gpg_secret_key = self.gpg_secret_keys[0]
|
||||||
|
log.info(f"""Found key id "{self.gpg_secret_key.fpr}" matching "{self.username}".""")
|
||||||
|
log.debug("key.gpg_secret_key.expired=%s" % self.gpg_secret_key.expired)
|
||||||
|
log.debug("key.gpg_secret_key.fpr=%s" % self.gpg_secret_key.fpr)
|
||||||
|
log.debug("key.gpg_secret_key.revoked=%s" % self.gpg_secret_key.revoked)
|
||||||
|
log.debug("key.gpg_secret_key.uids=%s" % self.gpg_secret_key.uids)
|
||||||
|
log.debug("key.gpg_secret_key.owner_trust=%s" % self.gpg_secret_key.owner_trust)
|
||||||
|
log.debug("key.gpg_secret_key.last_update=%s" % self.gpg_secret_key.last_update)
|
||||||
|
if self.password:
|
||||||
|
self.gpg.set_pinentry_mode(gpg.constants.PINENTRY_MODE_LOOPBACK)
|
||||||
|
self.pgp_public_armor = self.gpg.key_export(self.gpg_secret_key.fpr)
|
||||||
|
self.pgp_secret_armor = self.gpg.key_export_secret(self.gpg_secret_key.fpr)
|
||||||
|
log.debug("key.pgp_secret_armor=%s" % self.pgp_secret_armor)
|
||||||
|
if not self.pgp_secret_armor:
|
||||||
|
log.error(f"""Unable to export gpg secret key id "{self.gpg_secret_key.fpr}" of user "{self.username}". Please check your password!""")
|
||||||
|
exit(2)
|
||||||
|
with warnings.catch_warnings():
|
||||||
|
# remove CryptographyDeprecationWarning about deprecated
|
||||||
|
# SymmetricKeyAlgorithm IDEA, CAST5 and Blowfish (PGPy v0.5.4)
|
||||||
|
warnings.simplefilter('ignore')
|
||||||
|
self.pgpy, _ = pgpy.PGPKey.from_blob(self.pgp_secret_armor)
|
||||||
|
except Exception as e:
|
||||||
|
log.error(f'Unable to get pgpy from gpg: {e}')
|
||||||
|
exit(2)
|
||||||
|
|
||||||
|
def to_proto2(self):
|
||||||
|
log.debug("key.to_proto2()")
|
||||||
|
raise NotImplementedError(f"to_proto2() is not implemented for algorithm {self.algorithm}")
|
||||||
|
|
|
@ -0,0 +1,214 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
# link: https://git.p2p.legal/aya/dpgpid/
|
||||||
|
# desc: dpgpid builds a decentralized gpg world of trust with did over ipfs
|
||||||
|
|
||||||
|
# Copyleft 2022 Yann Autissier <aya@asycn.io>
|
||||||
|
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU Affero General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU Affero General Public License for more details.
|
||||||
|
|
||||||
|
# You should have received a copy of the GNU Affero General Public License
|
||||||
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
from . import key
|
||||||
|
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
|
||||||
|
from cryptography.hazmat.primitives import serialization
|
||||||
|
from SecureBytes import clearmem
|
||||||
|
import duniterpy.key
|
||||||
|
import logging as log
|
||||||
|
|
||||||
|
def from_duniterpy(duniterpy):
|
||||||
|
log.debug("ed25519.from_duniterpy(%s)" % duniterpy)
|
||||||
|
try:
|
||||||
|
return ed25519(duniterpy.sk[:32])
|
||||||
|
except Exception as e:
|
||||||
|
log.error(f'Unable to get ed25519 from duniterpy: {e}')
|
||||||
|
exit(2)
|
||||||
|
|
||||||
|
def from_jwk(jwk):
|
||||||
|
log.debug("ed25519.from_jwk(%s)" % jwk)
|
||||||
|
try:
|
||||||
|
return ed25519(jwk._okp_pri().private_bytes(
|
||||||
|
encoding=serialization.Encoding.Raw,
|
||||||
|
format=serialization.PrivateFormat.Raw,
|
||||||
|
encryption_algorithm=serialization.NoEncryption()
|
||||||
|
))
|
||||||
|
except Exception as e:
|
||||||
|
log.error(f'Unable to get ed25519 from jwk: {e}')
|
||||||
|
exit(2)
|
||||||
|
|
||||||
|
def from_libp2p(libp2p):
|
||||||
|
log.debug("ed25519.from_libp2p(%s) % libp2p")
|
||||||
|
try:
|
||||||
|
return ed25519(libp2p.lstrip(b'\x08\x01\x12@')[:32])
|
||||||
|
except Exception as e:
|
||||||
|
log.error(f'Unable to get ed25519 from libp2p: {e}')
|
||||||
|
exit(2)
|
||||||
|
|
||||||
|
def from_pem(pem):
|
||||||
|
log.debug("ed25519.from_pem()")
|
||||||
|
try:
|
||||||
|
return ed25519(serialization.load_pem_private_key(pem, password=None).private_bytes(
|
||||||
|
encoding=serialization.Encoding.Raw,
|
||||||
|
format=serialization.PrivateFormat.Raw,
|
||||||
|
encryption_algorithm=serialization.NoEncryption()
|
||||||
|
))
|
||||||
|
except Exception as e:
|
||||||
|
log.error(f'Unable to get ed25519 from pem: {e}')
|
||||||
|
exit(2)
|
||||||
|
|
||||||
|
def from_pgpy(pgpy):
|
||||||
|
log.debug("ed25519.from_pgpy()")
|
||||||
|
try:
|
||||||
|
self.pgpy_key_type()
|
||||||
|
if self.pgpy_key_type == 'RSA':
|
||||||
|
log.debug("key.pgpy._key.keymaterial.p=%s" % self.pgpy._key.keymaterial.p)
|
||||||
|
log.debug("key.pgpy._key.keymaterial.q=%s" % self.pgpy._key.keymaterial.q)
|
||||||
|
# rsa custom seed: sha256 hash of (p + q), where + is a string concatenation
|
||||||
|
# self.ed25519_seed_bytes = nacl.bindings.crypto_hash_sha256((rsa_int).to_bytes(rsa_len,byteorder='big'))
|
||||||
|
rsa_int = int(str(self.pgpy._key.keymaterial.p) + str(self.pgpy._key.keymaterial.q))
|
||||||
|
rsa_len = (rsa_int.bit_length() + 7) // 8
|
||||||
|
from cryptography.hazmat.primitives import hashes
|
||||||
|
digest = hashes.Hash(hashes.SHA256())
|
||||||
|
digest.update((rsa_int).to_bytes(rsa_len,byteorder='big'))
|
||||||
|
seed_bytes = digest.finalize()
|
||||||
|
# seed_bytes = nacl.bindings.crypto_hash_sha256((rsa_int).to_bytes(rsa_len,byteorder='big'))
|
||||||
|
elif self.pgpy_key_type in ('ECDSA', 'EdDSA', 'ECDH'):
|
||||||
|
log.debug("key.pgpy._key.keymaterial.s=%s" % self.pgpy._key.keymaterial.s)
|
||||||
|
seed_bytes = self.pgpy._key.keymaterial.s.to_bytes(32, byteorder='big')
|
||||||
|
else:
|
||||||
|
raise NotImplementedError(f"getting seed from pgp key type {self.pgpy_key_type} is not implemented")
|
||||||
|
return ed25519(seed_bytes)
|
||||||
|
except Exception as e:
|
||||||
|
log.error(f'Unable to get ed25519 from pgpy: {e}')
|
||||||
|
exit(2)
|
||||||
|
|
||||||
|
def pgpy_key_type(self):
|
||||||
|
log.debug("keygen.pgpy_key_type()")
|
||||||
|
if isinstance(self.pgpy._key.keymaterial, pgpy.packet.fields.RSAPriv):
|
||||||
|
self.pgpy_key_type = 'RSA'
|
||||||
|
elif isinstance(self.pgpy._key.keymaterial, pgpy.packet.fields.DSAPriv):
|
||||||
|
self.pgpy_key_type = 'DSA'
|
||||||
|
elif isinstance(self.pgpy._key.keymaterial, pgpy.packet.fields.ElGPriv):
|
||||||
|
self.pgpy_key_type = 'ElGamal'
|
||||||
|
elif isinstance(self.pgpy._key.keymaterial, pgpy.packet.fields.ECDSAPriv):
|
||||||
|
self.pgpy_key_type = 'ECDSA'
|
||||||
|
elif isinstance(self.pgpy._key.keymaterial, pgpy.packet.fields.EdDSAPriv):
|
||||||
|
self.pgpy_key_type = 'EdDSA'
|
||||||
|
elif isinstance(self.pgpy._key.keymaterial, pgpy.packet.fields.ECDHPriv):
|
||||||
|
self.pgpy_key_type = 'ECDH'
|
||||||
|
else:
|
||||||
|
self.pgpy_key_type = 'undefined'
|
||||||
|
log.debug("keygen.pgpy_key_type=%s" % self.pgpy_key_type)
|
||||||
|
|
||||||
|
class ed25519(key):
|
||||||
|
def __init__(self, seed: bytes):
|
||||||
|
super().__init__()
|
||||||
|
self.algorithm = 'ed25519'
|
||||||
|
self.cryptography = Ed25519PrivateKey.from_private_bytes(seed)
|
||||||
|
self.public_bytes = self.cryptography.public_key().public_bytes(
|
||||||
|
encoding=serialization.Encoding.Raw,
|
||||||
|
format=serialization.PublicFormat.Raw,
|
||||||
|
)
|
||||||
|
self.secret_bytes = seed + self.public_bytes
|
||||||
|
self.seed_bytes = seed
|
||||||
|
log.debug("ed25519().seed_bytes=%s" % self.seed_bytes)
|
||||||
|
|
||||||
|
def _cleanup(self):
|
||||||
|
log.debug("ed25519()._cleanup()")
|
||||||
|
if hasattr(self, 'duniterpy'):
|
||||||
|
if hasattr(self.duniterpy, 'seed') and self.duniterpy.seed:
|
||||||
|
clearmem(self.duniterpy.seed)
|
||||||
|
log.debug("cleared: ed25519().duniterpy.seed")
|
||||||
|
if hasattr(self.duniterpy, 'sk') and self.duniterpy.sk:
|
||||||
|
clearmem(self.duniterpy.sk)
|
||||||
|
log.debug("cleared: ed25519().duniterpy.sk")
|
||||||
|
if hasattr(self, 'secret_b36mf') and self.secret_b36mf:
|
||||||
|
clearmem(self.secret_b36mf)
|
||||||
|
log.debug("cleared: ed25519().secret_b36mf")
|
||||||
|
if hasattr(self, 'secret_b58mf') and self.secret_b58mf:
|
||||||
|
clearmem(self.secret_b58mf)
|
||||||
|
log.debug("cleared: ed25519().secret_b58mf")
|
||||||
|
if hasattr(self, 'secret_b58mh') and self.secret_b58mh:
|
||||||
|
clearmem(self.secret_b58mh)
|
||||||
|
log.debug("cleared: ed25519().secret_b58mh")
|
||||||
|
if hasattr(self, 'secret_b64mh') and self.secret_b64mh:
|
||||||
|
clearmem(self.secret_b64mh)
|
||||||
|
log.debug("cleared: ed25519().secret_b64mh")
|
||||||
|
if hasattr(self, 'secret_base58') and self.secret_base58:
|
||||||
|
clearmem(self.secret_base58)
|
||||||
|
log.debug("cleared: ed25519().secret_base58")
|
||||||
|
if hasattr(self, 'secret_base64') and self.secret_base64:
|
||||||
|
clearmem(self.secret_base64)
|
||||||
|
log.debug("cleared: ed25519().secret_base64")
|
||||||
|
if hasattr(self, 'secret_bytes') and self.secret_bytes:
|
||||||
|
clearmem(self.secret_bytes)
|
||||||
|
log.debug("cleared: ed25519().secret_bytes")
|
||||||
|
if hasattr(self, 'secret_cidv1') and self.secret_cidv1:
|
||||||
|
clearmem(self.secret_cidv1)
|
||||||
|
log.debug("cleared: ed25519().secret_cidv1")
|
||||||
|
if hasattr(self, 'secret_libp2p') and self.secret_libp2p:
|
||||||
|
clearmem(self.secret_libp2p)
|
||||||
|
log.debug("cleared: ed25519().secret_libp2p")
|
||||||
|
if hasattr(self, 'secret_pem_pkcs8') and self.secret_pem_pkcs8:
|
||||||
|
clearmem(self.secret_pem_pkcs8)
|
||||||
|
log.debug("cleared: ed25519().secret_pem_pkcs8")
|
||||||
|
if hasattr(self, 'secret_proto2') and self.secret_proto2:
|
||||||
|
clearmem(self.secret_proto2)
|
||||||
|
log.debug("cleared: ed25519().secret_proto2")
|
||||||
|
if hasattr(self, 'seed_bytes') and self.seed_bytes:
|
||||||
|
clearmem(self.seed_bytes)
|
||||||
|
log.debug("cleared: ed25519().seed_bytes")
|
||||||
|
if hasattr(self, 'ipfs_privkey') and self.ipfs_privkey:
|
||||||
|
clearmem(self.ipfs_privkey)
|
||||||
|
log.debug("cleared: ed25519().ipfs_privkey")
|
||||||
|
if hasattr(self, 'jwk'):
|
||||||
|
if hasattr(self, 'secret_jwk') and self.secret_jwk:
|
||||||
|
clearmem(self.secret_jwk)
|
||||||
|
log.debug("cleared: ed25519().secret_jwk")
|
||||||
|
if hasattr(self.jwk, 'd') and self.jwk.d:
|
||||||
|
clearmem(self.jwk.d)
|
||||||
|
log.debug("cleared: ed25519().jwk.d")
|
||||||
|
if hasattr(self, 'pgp_secret_armor') and self.pgp_secret_armor:
|
||||||
|
clearmem(self.pgp_secret_armor)
|
||||||
|
log.debug("cleared: ed25519().pgp_secret_armor")
|
||||||
|
if hasattr(self, 'pgpy'):
|
||||||
|
if hasattr(self.pgpy._key.keymaterial, 'p') and self.pgpy._key.keymaterial.p and not isinstance(self.pgpy._key.keymaterial.p, pgpy.packet.fields.ECPoint):
|
||||||
|
clearmem(self.pgpy._key.keymaterial.p)
|
||||||
|
log.debug("cleared: ed25519().pgpy._key.material.p")
|
||||||
|
if hasattr(self.pgpy._key.keymaterial, 'q') and self.pgpy._key.keymaterial.q:
|
||||||
|
clearmem(self.pgpy._key.keymaterial.q)
|
||||||
|
log.debug("cleared: ed25519().pgpy._key.material.q")
|
||||||
|
if hasattr(self.pgpy._key.keymaterial, 's') and self.pgpy._key.keymaterial.s:
|
||||||
|
clearmem(self.pgpy._key.keymaterial.s)
|
||||||
|
log.debug("cleared: ed25519().pgpy._key.material.s")
|
||||||
|
|
||||||
|
def to_duniterpy(self):
|
||||||
|
log.debug("keygen.to_duniterpy()")
|
||||||
|
try:
|
||||||
|
if not hasattr(self, 'duniterpy'):
|
||||||
|
self.duniterpy = duniterpy.key.SigningKey(self.seed_bytes)
|
||||||
|
except Exception as e:
|
||||||
|
log.error(f'Unable to get duniterpy: {e}')
|
||||||
|
exit(2)
|
||||||
|
log.debug("keygen.duniterpy.seed: %s" % self.duniterpy.seed)
|
||||||
|
|
||||||
|
def to_proto2(self):
|
||||||
|
log.debug("key.to_proto2()")
|
||||||
|
try:
|
||||||
|
## libp2p Protocol Buffer serialization
|
||||||
|
self.public_proto2 = b'\x08\x01\x12 ' + self.public_bytes
|
||||||
|
self.secret_proto2 = b'\x08\x01\x12@' + self.secret_bytes
|
||||||
|
except Exception as e:
|
||||||
|
log.error(f'Unable to get proto2: {e}')
|
||||||
|
exit(2)
|
||||||
|
log.debug("key.public_proto2=%s" % self.public_proto2)
|
||||||
|
log.debug("key.secret_proto2=%s" % self.secret_proto2)
|
||||||
|
|
|
@ -0,0 +1,265 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
# link: https://git.p2p.legal/aya/dpgpid/
|
||||||
|
# desc: dpgpid builds a decentralized gpg world of trust with did over ipfs
|
||||||
|
|
||||||
|
# Copyleft 2022 Yann Autissier <aya@asycn.io>
|
||||||
|
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU Affero General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU Affero General Public License for more details.
|
||||||
|
|
||||||
|
# You should have received a copy of the GNU Affero General Public License
|
||||||
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import configparser
|
||||||
|
import logging as log
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from about import __version__
|
||||||
|
import key
|
||||||
|
|
||||||
|
class keygen:
|
||||||
|
def __init__(self):
|
||||||
|
self.parser = argparse.ArgumentParser(description="""
|
||||||
|
Generate ed25519 keys for duniter and ipfs from gpg.
|
||||||
|
It converts a gpg key, a duniter username/password, or any ed25519 key to
|
||||||
|
a duniter wallet or an IPFS key.""")
|
||||||
|
self.parser.add_argument(
|
||||||
|
"-d",
|
||||||
|
"--debug",
|
||||||
|
action="store_true",
|
||||||
|
help="show debug informations (WARNING: including SECRET KEY)",
|
||||||
|
)
|
||||||
|
self.parser.add_argument(
|
||||||
|
"-f",
|
||||||
|
"--format",
|
||||||
|
choices=['ewif', 'jwk', 'nacl','p2p','pem','pubsec','seed','wif'],
|
||||||
|
default=None,
|
||||||
|
dest="format",
|
||||||
|
help="output file format, default: pem (pkcs8)",
|
||||||
|
)
|
||||||
|
self.parser.add_argument(
|
||||||
|
"-g",
|
||||||
|
"--gpg",
|
||||||
|
action="store_true",
|
||||||
|
help="use gpg key with uid matched by username",
|
||||||
|
)
|
||||||
|
self.parser.add_argument(
|
||||||
|
"-i",
|
||||||
|
"--input",
|
||||||
|
dest="input",
|
||||||
|
help="read ed25519 key from file FILE, autodetect format: {credentials,ewif,jwk,nacl,mnemonic,p2p,pem,pubsec,seed,wif}",
|
||||||
|
metavar='FILE',
|
||||||
|
)
|
||||||
|
self.parser.add_argument(
|
||||||
|
"-k",
|
||||||
|
"--keys",
|
||||||
|
action="store_true",
|
||||||
|
help="show public and secret keys",
|
||||||
|
)
|
||||||
|
self.parser.add_argument(
|
||||||
|
"-m",
|
||||||
|
"--mnemonic",
|
||||||
|
action="store_true",
|
||||||
|
help="use username as a DUBP mnemonic passphrase",
|
||||||
|
)
|
||||||
|
self.parser.add_argument(
|
||||||
|
"-o",
|
||||||
|
"--output",
|
||||||
|
dest="output",
|
||||||
|
default=None,
|
||||||
|
help="write ed25519 key to file FILE",
|
||||||
|
metavar='FILE',
|
||||||
|
)
|
||||||
|
self.parser.add_argument(
|
||||||
|
"-p",
|
||||||
|
"--password",
|
||||||
|
dest="password",
|
||||||
|
help="user password for duniter, gpg key and file encryption",
|
||||||
|
)
|
||||||
|
self.parser.add_argument(
|
||||||
|
"-q",
|
||||||
|
"--quiet",
|
||||||
|
action="store_true",
|
||||||
|
help="show only errors",
|
||||||
|
)
|
||||||
|
self.parser.add_argument(
|
||||||
|
"-s",
|
||||||
|
"--secret",
|
||||||
|
action="store_true",
|
||||||
|
help="show only secret key",
|
||||||
|
)
|
||||||
|
self.parser.add_argument(
|
||||||
|
"-t",
|
||||||
|
"--type",
|
||||||
|
choices=['b36mf', 'b58mf', 'b58mh','b64mh','base58','base64','duniter','ipfs','jwk'],
|
||||||
|
default="base58",
|
||||||
|
dest="type",
|
||||||
|
help="output text format, default: base58",
|
||||||
|
)
|
||||||
|
self.parser.add_argument(
|
||||||
|
"-v",
|
||||||
|
"--verbose",
|
||||||
|
action="store_true",
|
||||||
|
help="show more informations",
|
||||||
|
)
|
||||||
|
self.parser.add_argument(
|
||||||
|
"--version",
|
||||||
|
action="store_true",
|
||||||
|
help="show version and exit",
|
||||||
|
)
|
||||||
|
self.parser.add_argument(
|
||||||
|
'username',
|
||||||
|
help="username, mnemonic or gpg key",
|
||||||
|
nargs="*",
|
||||||
|
)
|
||||||
|
|
||||||
|
def _check_args(self, args):
|
||||||
|
log.debug("keygen._check_args(%s)" % args)
|
||||||
|
if self.input is None and not len(self.username):
|
||||||
|
self.parser.error('keygen requires an input file or a 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._cli(%s)" % argv)
|
||||||
|
|
||||||
|
self._check_args(args)
|
||||||
|
self._load_config()
|
||||||
|
self.key = key.from_args(args, self.config)
|
||||||
|
method = getattr(self, f'do_{self.type}', self._invalid_type)
|
||||||
|
return method()
|
||||||
|
|
||||||
|
def _invalid_type(self):
|
||||||
|
log.debug("keygen._invalid_type()")
|
||||||
|
self.parser.error(f"type {self.type} is not valid.")
|
||||||
|
|
||||||
|
def _load_config(self):
|
||||||
|
log.debug("keygen._load_config()")
|
||||||
|
self.config = configparser.RawConfigParser()
|
||||||
|
config_dir = os.path.join(os.environ.get('XDG_CONFIG_HOME', os.path.expanduser('~/.config')), 'dpgpid')
|
||||||
|
log.debug("config_dir=%s" % config_dir)
|
||||||
|
self.config.read( [config_dir + '/keygen.conf'] )
|
||||||
|
|
||||||
|
def _output(self):
|
||||||
|
log.debug("keygen._output()")
|
||||||
|
if self.output is None:
|
||||||
|
self._output_text()
|
||||||
|
else:
|
||||||
|
self._output_file()
|
||||||
|
os.chmod(self.output, 0o600)
|
||||||
|
|
||||||
|
def _output_file(self):
|
||||||
|
log.debug("keygen._output_file()")
|
||||||
|
self.key.to_file(self.output, self.format, self.password)
|
||||||
|
|
||||||
|
def _output_text(self):
|
||||||
|
log.debug("keygen()._output_text()")
|
||||||
|
if self.keys or not self.secret:
|
||||||
|
print("%s" % self.public_key)
|
||||||
|
if self.keys or self.secret:
|
||||||
|
print("%s" % self.secret_key)
|
||||||
|
|
||||||
|
def do_b36mf(self):
|
||||||
|
log.debug("keygen.do_b36mf()")
|
||||||
|
self.key.to_b36mf()
|
||||||
|
self.public_key = self.key.public_b36mf
|
||||||
|
self.secret_key = self.key.secret_b36mf
|
||||||
|
self._output()
|
||||||
|
|
||||||
|
def do_b58mf(self):
|
||||||
|
log.debug("keygen.do_b58mf()")
|
||||||
|
self.key.to_b58mf()
|
||||||
|
self.public_key = self.key.public_b58mf
|
||||||
|
self.secret_key = self.key.secret_b58mf
|
||||||
|
self._output()
|
||||||
|
|
||||||
|
def do_b58mh(self):
|
||||||
|
log.debug("keygen.do_b58mh()")
|
||||||
|
self.key.to_b58mh()
|
||||||
|
self.public_key = self.key.public_b58mh
|
||||||
|
self.secret_key = self.key.secret_b58mh
|
||||||
|
self._output()
|
||||||
|
|
||||||
|
def do_b64mh(self):
|
||||||
|
log.debug("keygen.do_b64mh()")
|
||||||
|
self.key.to_b64mh()
|
||||||
|
self.public_key = self.key.public_b64mh
|
||||||
|
self.secret_key = self.key.secret_b64mh
|
||||||
|
self._output()
|
||||||
|
|
||||||
|
def do_base58(self):
|
||||||
|
log.debug("keygen.do_base58()")
|
||||||
|
self.key.to_base58()
|
||||||
|
self.public_key = self.key.public_base58
|
||||||
|
self.secret_key = self.key.secret_base58
|
||||||
|
self._output()
|
||||||
|
|
||||||
|
def do_base64(self):
|
||||||
|
log.debug("keygen.do_base64()")
|
||||||
|
self.key.to_base64()
|
||||||
|
self.public_key = self.key.public_base64
|
||||||
|
self.secret_key = self.key.secret_base64
|
||||||
|
self._output()
|
||||||
|
|
||||||
|
def do_duniter(self):
|
||||||
|
log.debug("keygen.do_duniter()")
|
||||||
|
if not self.format:
|
||||||
|
self.format = 'pubsec'
|
||||||
|
self.key.to_base58()
|
||||||
|
self.public_key = self.key.public_base58
|
||||||
|
self.secret_key = self.key.secret_base58
|
||||||
|
self._output()
|
||||||
|
|
||||||
|
def do_ipfs(self):
|
||||||
|
log.debug("keygen.do_ipfs()")
|
||||||
|
self.key.to_b58mh()
|
||||||
|
self.key.to_b64mh()
|
||||||
|
self.public_key = self.key.public_b58mh
|
||||||
|
self.secret_key = self.key.secret_b64mh
|
||||||
|
self._output()
|
||||||
|
|
||||||
|
def do_jwk(self):
|
||||||
|
log.debug("keygen.do_jwk()")
|
||||||
|
self.key.to_jwk()
|
||||||
|
self.public_key = self.key.public_jwk
|
||||||
|
self.secret_key = self.key.secret_jwk
|
||||||
|
self._output()
|
||||||
|
|
||||||
|
def main(argv=None):
|
||||||
|
if argv is None:
|
||||||
|
argv = sys.argv[1:]
|
||||||
|
return keygen()._cli(argv)
|
||||||
|
|
||||||
|
def version(version=__version__):
|
||||||
|
print("%s v%s" % (sys.argv[0],version))
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
sys.exit(main())
|
||||||
|
|
934
keygen.py
934
keygen.py
|
@ -1,934 +0,0 @@
|
||||||
#!/usr/bin/env python3
|
|
||||||
# link: https://git.p2p.legal/aya/dpgpid/
|
|
||||||
# desc: generate ed25519 keys for duniter and ipfs from gpg
|
|
||||||
|
|
||||||
# Copyleft 2022 Yann Autissier <aya@asycn.io>
|
|
||||||
# all crypto science belongs to Pascal Engélibert <tuxmain@zettascript.org>
|
|
||||||
# coming from files available at https://git.p2p.legal/qo-op/Astroport.ONE/tools
|
|
||||||
# gpgme stuff has been provided by Ben McGinnes
|
|
||||||
# and comes from http://files.au.adversary.org/crypto/gpgme-python-howto.html
|
|
||||||
# gpg key extraction is taken from work of Simon Vareille available at
|
|
||||||
# https://gist.github.com/SimonVareille/fda49baf5f3e15b5c88e25560aeb2822
|
|
||||||
|
|
||||||
# This program is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU Affero General Public License as published by
|
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU Affero General Public License for more details.
|
|
||||||
|
|
||||||
# You should have received a copy of the GNU Affero General Public License
|
|
||||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
import argparse
|
|
||||||
import base36
|
|
||||||
import base58
|
|
||||||
import base64
|
|
||||||
import configparser
|
|
||||||
from cryptography.hazmat.primitives.asymmetric import ed25519
|
|
||||||
from cryptography.hazmat.primitives import serialization
|
|
||||||
import duniterpy.key
|
|
||||||
import gpg
|
|
||||||
from jwcrypto import jwk
|
|
||||||
import logging as log
|
|
||||||
import nacl.bindings
|
|
||||||
import nacl.encoding
|
|
||||||
import pgpy
|
|
||||||
import pynentry
|
|
||||||
from SecureBytes import clearmem
|
|
||||||
import os
|
|
||||||
import re
|
|
||||||
import struct
|
|
||||||
import sys
|
|
||||||
import time
|
|
||||||
import warnings
|
|
||||||
|
|
||||||
__version__='0.0.5'
|
|
||||||
|
|
||||||
class keygen:
|
|
||||||
def __init__(self):
|
|
||||||
self.parser = argparse.ArgumentParser(description="""
|
|
||||||
Generate ed25519 keys for duniter and ipfs from gpg.
|
|
||||||
It converts a gpg key, a duniter username/password, or any ed25519 key to
|
|
||||||
a duniter wallet or an IPFS key.""")
|
|
||||||
self.parser.add_argument(
|
|
||||||
"-d",
|
|
||||||
"--debug",
|
|
||||||
action="store_true",
|
|
||||||
help="show debug informations (WARNING: including SECRET KEY)",
|
|
||||||
)
|
|
||||||
self.parser.add_argument(
|
|
||||||
"-f",
|
|
||||||
"--format",
|
|
||||||
choices=['ewif', 'jwk', 'nacl','p2p','pem','pubsec','seed','wif'],
|
|
||||||
default=None,
|
|
||||||
dest="format",
|
|
||||||
help="output file format, default: pem (pkcs8)",
|
|
||||||
)
|
|
||||||
self.parser.add_argument(
|
|
||||||
"-g",
|
|
||||||
"--gpg",
|
|
||||||
action="store_true",
|
|
||||||
help="use gpg key with uid matched by username",
|
|
||||||
)
|
|
||||||
self.parser.add_argument(
|
|
||||||
"-i",
|
|
||||||
"--input",
|
|
||||||
dest="input",
|
|
||||||
help="read ed25519 key from file FILE, autodetect format: {credentials,ewif,jwk,nacl,mnemonic,p2p,pem,pubsec,seed,wif}",
|
|
||||||
metavar='FILE',
|
|
||||||
)
|
|
||||||
self.parser.add_argument(
|
|
||||||
"-k",
|
|
||||||
"--keys",
|
|
||||||
action="store_true",
|
|
||||||
help="show public and secret keys",
|
|
||||||
)
|
|
||||||
self.parser.add_argument(
|
|
||||||
"-m",
|
|
||||||
"--mnemonic",
|
|
||||||
action="store_true",
|
|
||||||
help="use username as a DUBP mnemonic passphrase",
|
|
||||||
)
|
|
||||||
self.parser.add_argument(
|
|
||||||
"-o",
|
|
||||||
"--output",
|
|
||||||
dest="output",
|
|
||||||
default=None,
|
|
||||||
help="write ed25519 key to file FILE",
|
|
||||||
metavar='FILE',
|
|
||||||
)
|
|
||||||
self.parser.add_argument(
|
|
||||||
"-p",
|
|
||||||
"--prefix",
|
|
||||||
action="store_true",
|
|
||||||
help="prefix output text with key type",
|
|
||||||
)
|
|
||||||
self.parser.add_argument(
|
|
||||||
"-q",
|
|
||||||
"--quiet",
|
|
||||||
action="store_true",
|
|
||||||
help="show only errors",
|
|
||||||
)
|
|
||||||
self.parser.add_argument(
|
|
||||||
"-s",
|
|
||||||
"--secret",
|
|
||||||
action="store_true",
|
|
||||||
help="show only secret key",
|
|
||||||
)
|
|
||||||
self.parser.add_argument(
|
|
||||||
"-t",
|
|
||||||
"--type",
|
|
||||||
choices=['b36mf', 'b58mf', 'b58mh','b64mh','base58','base64','duniter','ipfs','jwk'],
|
|
||||||
default="base58",
|
|
||||||
dest="type",
|
|
||||||
help="output text format, default: base58",
|
|
||||||
)
|
|
||||||
self.parser.add_argument(
|
|
||||||
"-v",
|
|
||||||
"--verbose",
|
|
||||||
action="store_true",
|
|
||||||
help="show more informations",
|
|
||||||
)
|
|
||||||
self.parser.add_argument(
|
|
||||||
"--version",
|
|
||||||
action="store_true",
|
|
||||||
help="show version and exit",
|
|
||||||
)
|
|
||||||
self.parser.add_argument(
|
|
||||||
'username',
|
|
||||||
nargs="?",
|
|
||||||
)
|
|
||||||
self.parser.add_argument(
|
|
||||||
'password',
|
|
||||||
nargs="?",
|
|
||||||
)
|
|
||||||
|
|
||||||
def _check_args(self, args):
|
|
||||||
log.debug("keygen._check_args(%s)" % args)
|
|
||||||
if self.input is None and self.username is None:
|
|
||||||
self.parser.error('keygen requires an input file or a username')
|
|
||||||
|
|
||||||
def _cleanup(self):
|
|
||||||
log.debug("keygen._cleanup()")
|
|
||||||
if hasattr(self, 'duniterpy'):
|
|
||||||
if hasattr(self.duniterpy, 'seed') and self.duniterpy.seed:
|
|
||||||
clearmem(self.duniterpy.seed)
|
|
||||||
log.debug("cleared: keygen.duniterpy.seed")
|
|
||||||
if hasattr(self.duniterpy, 'sk') and self.duniterpy.sk:
|
|
||||||
clearmem(self.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:
|
|
||||||
clearmem(self.ed25519_secret_base58)
|
|
||||||
log.debug("cleared: keygen.ed25519_secret_base58")
|
|
||||||
if hasattr(self, 'ed25519_secret_base64') and self.ed25519_secret_base64:
|
|
||||||
clearmem(self.ed25519_secret_base64)
|
|
||||||
log.debug("cleared: keygen.ed25519_secret_base64")
|
|
||||||
if hasattr(self, 'ed25519_secret_bytes') and self.ed25519_secret_bytes:
|
|
||||||
clearmem(self.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:
|
|
||||||
clearmem(self.ed25519_secret_pem_pkcs8)
|
|
||||||
log.debug("cleared: keygen.ed25515_secret_pem_pkcs8")
|
|
||||||
if hasattr(self, 'ed25519_secret_libp2p') and self.ed25519_secret_libp2p:
|
|
||||||
clearmem(self.ed25519_secret_libp2p)
|
|
||||||
log.debug("cleared: keygen.ed25515_secret_libp2p")
|
|
||||||
if hasattr(self, 'ed25519_seed_bytes') and self.ed25519_seed_bytes:
|
|
||||||
clearmem(self.ed25519_seed_bytes)
|
|
||||||
log.debug("cleared: keygen.ed25519_seed_bytes")
|
|
||||||
if hasattr(self, 'ipfs_privkey') and self.ipfs_privkey:
|
|
||||||
clearmem(self.ipfs_privkey)
|
|
||||||
log.debug("cleared: keygen.ipfs_privkey")
|
|
||||||
if hasattr(self, 'jwk'):
|
|
||||||
if hasattr(self, 'ed25519_secret_jwk') and self.ed25519_secret_jwk:
|
|
||||||
clearmem(self.ed25519_secret_jwk)
|
|
||||||
log.debug("cleared: keygen.ed25519_secret_jwk")
|
|
||||||
if hasattr(self.jwk, 'd') and self.jwk.d:
|
|
||||||
clearmem(self.jwk.d)
|
|
||||||
log.debug("cleared: keygen.jwk.d")
|
|
||||||
if hasattr(self, 'password') and self.password:
|
|
||||||
clearmem(self.password)
|
|
||||||
log.debug("cleared: keygen.password")
|
|
||||||
if hasattr(self, 'pgp_secret_armor') and self.pgp_secret_armor:
|
|
||||||
clearmem(self.pgp_secret_armor)
|
|
||||||
log.debug("cleared: keygen.pgp_secret_armor")
|
|
||||||
if hasattr(self, 'pgpy'):
|
|
||||||
if hasattr(self.pgpy._key.keymaterial, 'p') and self.pgpy._key.keymaterial.p and not isinstance(self.pgpy._key.keymaterial.p, pgpy.packet.fields.ECPoint):
|
|
||||||
clearmem(self.pgpy._key.keymaterial.p)
|
|
||||||
log.debug("cleared: keygen.pgpy._key.material.p")
|
|
||||||
if hasattr(self.pgpy._key.keymaterial, 'q') and self.pgpy._key.keymaterial.q:
|
|
||||||
clearmem(self.pgpy._key.keymaterial.q)
|
|
||||||
log.debug("cleared: keygen.pgpy._key.material.q")
|
|
||||||
if hasattr(self.pgpy._key.keymaterial, 's') and self.pgpy._key.keymaterial.s:
|
|
||||||
clearmem(self.pgpy._key.keymaterial.s)
|
|
||||||
log.debug("cleared: keygen.pgpy._key.material.s")
|
|
||||||
if hasattr(self, 'username') and self.username:
|
|
||||||
clearmem(self.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):
|
|
||||||
log.debug("keygen._invalid_type()")
|
|
||||||
self.parser.error(f"type {self.type} is not valid.")
|
|
||||||
|
|
||||||
def _load_config(self):
|
|
||||||
log.debug("keygen._load_config()")
|
|
||||||
self.config = configparser.RawConfigParser()
|
|
||||||
config_dir = os.path.join(os.environ.get('XDG_CONFIG_HOME', os.path.expanduser('~/.config')), 'dpgpid')
|
|
||||||
log.debug("config_dir=%s" % config_dir)
|
|
||||||
self.config.read( [config_dir + '/keygen.conf'] )
|
|
||||||
|
|
||||||
def _output(self, public_key, secret_key, public_key_prefix, secret_key_prefix):
|
|
||||||
log.debug("keygen._output()")
|
|
||||||
if self.output is None:
|
|
||||||
self._output_text(public_key, secret_key, public_key_prefix, secret_key_prefix)
|
|
||||||
else:
|
|
||||||
self._output_file()
|
|
||||||
os.chmod(self.output, 0o600)
|
|
||||||
self._cleanup()
|
|
||||||
|
|
||||||
def _output_file(self):
|
|
||||||
log.debug("keygen._output_file()")
|
|
||||||
try:
|
|
||||||
if self.format == 'dewif':
|
|
||||||
if not hasattr(self, 'duniterpy'):
|
|
||||||
self.duniterpy_from_ed25519_seed_bytes()
|
|
||||||
if not self.password:
|
|
||||||
with pynentry.PynEntry() as p:
|
|
||||||
p.description = f"""Data in DEWIF file needs to be encrypted.
|
|
||||||
Please enter a password to encrypt seed.
|
|
||||||
"""
|
|
||||||
p.prompt = 'Passphrase:'
|
|
||||||
try:
|
|
||||||
self.password = p.get_pin()
|
|
||||||
except pynentry.PinEntryCancelled:
|
|
||||||
log.warning('Cancelled! Goodbye.')
|
|
||||||
self._cleanup()
|
|
||||||
exit(1)
|
|
||||||
self.duniterpy.save_dewif_v1_file(self.output, self.password)
|
|
||||||
elif self.format == 'ewif':
|
|
||||||
if not hasattr(self, 'duniterpy'):
|
|
||||||
self.duniterpy_from_ed25519_seed_bytes()
|
|
||||||
if not self.password:
|
|
||||||
with pynentry.PynEntry() as p:
|
|
||||||
p.description = f"""Data in EWIF file needs to be encrypted.
|
|
||||||
Please enter a password to encrypt seed.
|
|
||||||
"""
|
|
||||||
p.prompt = 'Passphrase:'
|
|
||||||
try:
|
|
||||||
self.password = p.get_pin()
|
|
||||||
except pynentry.PinEntryCancelled:
|
|
||||||
log.warning('Cancelled! Goodbye.')
|
|
||||||
self._cleanup()
|
|
||||||
exit(1)
|
|
||||||
self.duniterpy.save_ewif_file(self.output, self.password)
|
|
||||||
elif self.format == 'jwk':
|
|
||||||
if not hasattr(self, 'jwk'):
|
|
||||||
self.jwk_from_ed25519()
|
|
||||||
with open(self.output, "w") as file:
|
|
||||||
file.write(self.jwk.export())
|
|
||||||
elif self.format == 'nacl':
|
|
||||||
if not hasattr(self, 'duniterpy'):
|
|
||||||
self.duniterpy_from_ed25519_seed_bytes()
|
|
||||||
self.duniterpy.save_private_key(self.output)
|
|
||||||
elif self.format == 'p2p':
|
|
||||||
if not hasattr(self, 'ed25519_secret_libp2p'):
|
|
||||||
self.libp2p_from_ed25519()
|
|
||||||
with open(self.output, "wb") as file:
|
|
||||||
file.write(self.ed25519_secret_libp2p)
|
|
||||||
elif self.format == 'pubsec':
|
|
||||||
if not hasattr(self, 'duniterpy'):
|
|
||||||
self.duniterpy_from_ed25519_seed_bytes()
|
|
||||||
self.duniterpy.save_pubsec_file(self.output)
|
|
||||||
elif self.format == 'seed':
|
|
||||||
if not hasattr(self, 'duniterpy'):
|
|
||||||
self.duniterpy_from_ed25519_seed_bytes()
|
|
||||||
self.duniterpy.save_seedhex_file(self.output)
|
|
||||||
elif self.format == 'wif':
|
|
||||||
if not hasattr(self, 'duniterpy'):
|
|
||||||
self.duniterpy_from_ed25519_seed_bytes()
|
|
||||||
self.duniterpy.save_wif_file(self.output)
|
|
||||||
else:
|
|
||||||
if not hasattr(self, 'ed25519_secret_pem_pkcs8'):
|
|
||||||
self.pem_pkcs8_from_ed25519()
|
|
||||||
with open(self.output, "w") as file:
|
|
||||||
file.write(self.ed25519_secret_pem_pkcs8)
|
|
||||||
except Exception as e:
|
|
||||||
log.error(f'Unable to output file {self.output}: {e}')
|
|
||||||
self._cleanup()
|
|
||||||
exit(2)
|
|
||||||
|
|
||||||
def _output_text(self, public_key, secret_key, public_key_prefix, secret_key_prefix):
|
|
||||||
log.debug("keygen._output_text()")
|
|
||||||
if self.keys or not self.secret:
|
|
||||||
print("%s" % ''.join([self.prefix * public_key_prefix, public_key]))
|
|
||||||
if self.keys or self.secret:
|
|
||||||
print("%s" % ''.join([self.prefix * secret_key_prefix, secret_key]))
|
|
||||||
|
|
||||||
def b36mf_from_cidv1(self):
|
|
||||||
log.debug("keygen.b36mf_from_cidv1()")
|
|
||||||
if not hasattr(self, 'ed25519_public_cidv1') or not hasattr(self, 'ed25519_secret_cidv1'):
|
|
||||||
self.cidv1_from_libp2p()
|
|
||||||
try:
|
|
||||||
self.ed25519_public_b36mf = 'k' + base36.dumps(int.from_bytes(self.ed25519_public_cidv1, byteorder='big'))
|
|
||||||
self.ed25519_secret_b36mf = 'k' + base36.dumps(int.from_bytes(self.ed25519_secret_cidv1, byteorder='big'))
|
|
||||||
except Exception as 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()
|
|
||||||
exit(2)
|
|
||||||
log.debug("keygen.ed25519_public_b58mh=%s" % self.ed25519_public_b58mh)
|
|
||||||
log.debug("keygen.ed25519_secret_b58mh=%s" % self.ed25519_secret_b58mh)
|
|
||||||
|
|
||||||
def b64mh_from_libp2p(self):
|
|
||||||
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:
|
|
||||||
self.ed25519_public_b64mh = base64.b64encode(self.ed25519_public_libp2p).decode('ascii')
|
|
||||||
self.ed25519_secret_b64mh = base64.b64encode(self.ed25519_secret_libp2p).decode('ascii')
|
|
||||||
except Exception as e:
|
|
||||||
log.error(f'Unable to get b64mh from libp2p: {e}')
|
|
||||||
self._cleanup()
|
|
||||||
exit(2)
|
|
||||||
log.debug("keygen.ed25519_public_b64mh=%s" % self.ed25519_public_b64mh)
|
|
||||||
log.debug("keygen.ed25519_secret_b64mh=%s" % self.ed25519_secret_b64mh)
|
|
||||||
|
|
||||||
def base58_from_ed25519(self):
|
|
||||||
log.debug("keygen.base58_from_ed25519()")
|
|
||||||
try:
|
|
||||||
self.ed25519_public_base58 = base58.b58encode(self.ed25519_public_bytes).decode('ascii')
|
|
||||||
self.ed25519_secret_base58 = base58.b58encode(self.ed25519_secret_bytes).decode('ascii')
|
|
||||||
except Exception as e:
|
|
||||||
log.error(f'Unable to get base58 from ed25519: {e}')
|
|
||||||
self._cleanup()
|
|
||||||
exit(2)
|
|
||||||
log.debug("keygen.ed25519_public_base58=%s" % self.ed25519_public_base58)
|
|
||||||
log.debug("keygen.ed25519_secret_base58=%s" % self.ed25519_secret_base58)
|
|
||||||
|
|
||||||
def base64_from_ed25519(self):
|
|
||||||
log.debug("keygen.base64_from_ed25519()")
|
|
||||||
try:
|
|
||||||
self.ed25519_public_base64 = base64.b64encode(self.ed25519_public_bytes).decode('ascii')
|
|
||||||
self.ed25519_secret_base64 = base64.b64encode(self.ed25519_secret_bytes).decode('ascii')
|
|
||||||
except Exception as e:
|
|
||||||
log.error(f'Unable to get base64 from ed25519: {e}')
|
|
||||||
self._cleanup()
|
|
||||||
exit(2)
|
|
||||||
log.debug("keygen.ed25519_public_base64=%s" % self.ed25519_public_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):
|
|
||||||
log.debug("keygen.do_b58mh()")
|
|
||||||
self.libp2p_from_ed25519()
|
|
||||||
self.b58mh_from_libp2p()
|
|
||||||
self._output(self.ed25519_public_b58mh, self.ed25519_secret_b58mh, 'pub: ', 'sec: ')
|
|
||||||
|
|
||||||
def do_b64mh(self):
|
|
||||||
log.debug("keygen.do_b64mh()")
|
|
||||||
self.libp2p_from_ed25519()
|
|
||||||
self.b64mh_from_libp2p()
|
|
||||||
self._output(self.ed25519_public_b64mh, self.ed25519_secret_b64mh, 'pub: ', 'sec: ')
|
|
||||||
|
|
||||||
def do_base58(self):
|
|
||||||
log.debug("keygen.do_base58()")
|
|
||||||
self.base58_from_ed25519()
|
|
||||||
self._output(self.ed25519_public_base58, self.ed25519_secret_base58, 'pub: ', 'sec: ')
|
|
||||||
|
|
||||||
def do_base64(self):
|
|
||||||
log.debug("keygen.do_base64()")
|
|
||||||
self.base64_from_ed25519()
|
|
||||||
self._output(self.ed25519_public_base64, self.ed25519_secret_base64, 'pub: ', 'sec: ')
|
|
||||||
|
|
||||||
def do_duniter(self):
|
|
||||||
log.debug("keygen.do_duniter()")
|
|
||||||
if not self.format:
|
|
||||||
self.format = 'pubsec'
|
|
||||||
self.base58_from_ed25519()
|
|
||||||
self._output(self.ed25519_public_base58, self.ed25519_secret_base58, 'pub: ', 'sec: ')
|
|
||||||
|
|
||||||
def do_ipfs(self):
|
|
||||||
log.debug("keygen.do_ipfs()")
|
|
||||||
self.libp2p_from_ed25519()
|
|
||||||
self.b58mh_from_libp2p()
|
|
||||||
self.b64mh_from_libp2p()
|
|
||||||
self._output(self.ed25519_public_b58mh, self.ed25519_secret_b64mh, 'PeerID: ', 'PrivKEY: ')
|
|
||||||
|
|
||||||
def do_jwk(self):
|
|
||||||
log.debug("keygen.do_jwk()")
|
|
||||||
self.jwk_from_ed25519()
|
|
||||||
self._output(self.ed25519_public_jwk, self.ed25519_secret_jwk, 'pub: ', 'sec: ')
|
|
||||||
|
|
||||||
def duniterpy_from_credentials(self):
|
|
||||||
log.debug("keygen.duniterpy_from_credentials()")
|
|
||||||
try:
|
|
||||||
scrypt_params = duniterpy.key.scrypt_params.ScryptParams(
|
|
||||||
int(self.config.get('scrypt', 'n')) if self.config.has_option('scrypt', 'n') else 4096,
|
|
||||||
int(self.config.get('scrypt', 'r')) if self.config.has_option('scrypt', 'r') else 16,
|
|
||||||
int(self.config.get('scrypt', 'p')) if self.config.has_option('scrypt', 'p') else 1,
|
|
||||||
int(self.config.get('scrypt', 'sl')) if self.config.has_option('scrypt', 'sl') else 32,
|
|
||||||
)
|
|
||||||
if not self.password:
|
|
||||||
with pynentry.PynEntry() as p:
|
|
||||||
p.description = f"""Please enter the passord for username "{self.username}"."""
|
|
||||||
p.prompt = 'Passsord:'
|
|
||||||
try:
|
|
||||||
self.password = p.get_pin()
|
|
||||||
except pynentry.PinEntryCancelled:
|
|
||||||
log.warning('Cancelled! Goodbye.')
|
|
||||||
self._cleanup()
|
|
||||||
exit(1)
|
|
||||||
self.duniterpy = duniterpy.key.SigningKey.from_credentials(
|
|
||||||
self.username,
|
|
||||||
self.password,
|
|
||||||
scrypt_params
|
|
||||||
)
|
|
||||||
except Exception as e:
|
|
||||||
log.error(f'Unable to get duniter from credentials: {e}')
|
|
||||||
self._cleanup()
|
|
||||||
exit(2)
|
|
||||||
log.debug("keygen.duniterpy.seed: %s" % self.duniterpy.seed)
|
|
||||||
|
|
||||||
def duniterpy_from_ed25519_seed_bytes(self):
|
|
||||||
log.debug("keygen.duniterpy_from_ed25519_seed_bytes()")
|
|
||||||
try:
|
|
||||||
self.duniterpy = duniterpy.key.SigningKey(self.ed25519_seed_bytes)
|
|
||||||
except Exception as e:
|
|
||||||
log.error(f'Unable to get duniterpy from ed25519 seed bytes: {e}')
|
|
||||||
self._cleanup()
|
|
||||||
exit(2)
|
|
||||||
log.debug("keygen.duniterpy.seed: %s" % self.duniterpy.seed)
|
|
||||||
|
|
||||||
def duniterpy_from_file(self):
|
|
||||||
log.debug("keygen.duniterpy_from_file()")
|
|
||||||
try:
|
|
||||||
with open(self.input, 'r') as file:
|
|
||||||
lines = file.readlines()
|
|
||||||
if len(lines) > 0:
|
|
||||||
line = lines[0].strip()
|
|
||||||
regex_ewif = re.compile('^Type: EWIF$')
|
|
||||||
regex_jwk = re.compile('^\\s*{\\s*"crv":\\s*"Ed25519",\\s*"d":\\s*"(.)+",\\s*"kty":\\s*"OKP",\\s*"x":\\s*"(.)+"\\s*}')
|
|
||||||
regex_nacl = re.compile('^\\s*{\\s*"priv":\\s*"[0-9a-fA-F]+",\\s*"verify":\\s*"[0-9a-fA-F]+",\\s*"sign":\\s*"[0-9a-fA-F]+"\\s*}')
|
|
||||||
regex_pem = re.compile('^-----BEGIN PRIVATE KEY-----$')
|
|
||||||
regex_pubsec = re.compile('^Type: PubSec$')
|
|
||||||
regex_seed = re.compile('^[0-9a-fA-F]{64}$')
|
|
||||||
regex_ssb = re.compile('\\s*{\\s*"curve":\\s*"ed25519",\\s*"public":\\s*"(.+)\\.ed25519",\\s*"private":\\s*"(.+)\\.ed25519",\\s*"id":\\s*"@(.+).ed25519"\\s*}')
|
|
||||||
regex_wif = re.compile('^Type: WIF$')
|
|
||||||
if re.search(regex_ewif, line):
|
|
||||||
log.info("input file format detected: ewif")
|
|
||||||
if not self.password:
|
|
||||||
with pynentry.PynEntry() as p:
|
|
||||||
p.description = f"""Data in EWIF file is encrypted.
|
|
||||||
Please enter a password to decrypt seed.
|
|
||||||
"""
|
|
||||||
p.prompt = 'Passphrase:'
|
|
||||||
try:
|
|
||||||
self.password = p.get_pin()
|
|
||||||
except pynentry.PinEntryCancelled:
|
|
||||||
log.warning('Cancelled! Goodbye.')
|
|
||||||
self._cleanup()
|
|
||||||
exit(1)
|
|
||||||
self.duniterpy = duniterpy.key.SigningKey.from_ewif_file(self.input, self.password)
|
|
||||||
elif re.search(regex_jwk, line):
|
|
||||||
log.info("input file format detected: jwk")
|
|
||||||
self.jwk_from_json(line)
|
|
||||||
self.ed25519_seed_bytes_from_jwk()
|
|
||||||
self.duniterpy_from_ed25519_seed_bytes()
|
|
||||||
elif re.search(regex_nacl, line):
|
|
||||||
log.info("input file format detected: nacl")
|
|
||||||
self.duniterpy = duniterpy.key.SigningKey.from_private_key(self.input)
|
|
||||||
elif re.search(regex_pem, line):
|
|
||||||
log.info("input file format detected: pem")
|
|
||||||
self.ed25519_seed_bytes_from_pem(''.join(lines).encode())
|
|
||||||
self.duniterpy_from_ed25519_seed_bytes()
|
|
||||||
elif re.search(regex_pubsec, line):
|
|
||||||
log.info("input file format detected: pubsec")
|
|
||||||
self.duniterpy = duniterpy.key.SigningKey.from_pubsec_file(self.input)
|
|
||||||
elif re.search(regex_seed, line):
|
|
||||||
log.info("input file format detected: seed")
|
|
||||||
self.duniterpy = duniterpy.key.SigningKey.from_seedhex_file(self.input)
|
|
||||||
elif re.search(regex_ssb, line):
|
|
||||||
log.info("input file format detected: ssb")
|
|
||||||
self.duniterpy = duniterpy.key.SigningKey.from_ssb_file(self.input)
|
|
||||||
elif re.search(regex_wif, line):
|
|
||||||
log.info("input file format detected: wif")
|
|
||||||
self.duniterpy = duniterpy.key.SigningKey.from_wif_file(self.input)
|
|
||||||
elif len(line.split(' ')) == 12:
|
|
||||||
log.info("input file format detected: mnemonic")
|
|
||||||
self.username = line
|
|
||||||
self.duniterpy_from_mnemonic()
|
|
||||||
elif len(lines) > 1:
|
|
||||||
log.info("input file format detected: credentials")
|
|
||||||
self.username = line
|
|
||||||
self.password = lines[1].strip()
|
|
||||||
self.duniterpy_from_credentials()
|
|
||||||
else:
|
|
||||||
raise NotImplementedError('unknown input file format.')
|
|
||||||
else:
|
|
||||||
raise NotImplementedError('empty file.')
|
|
||||||
except UnicodeDecodeError as e:
|
|
||||||
try:
|
|
||||||
with open(self.input, 'rb') as file:
|
|
||||||
lines = file.readlines()
|
|
||||||
if len(lines) > 0:
|
|
||||||
line = lines[0].strip()
|
|
||||||
regex_dewif = re.compile(b'^\x00\x00\x00\x01\x00\x00\x00\x01')
|
|
||||||
regex_p2p = re.compile(b'^\x08\x01\x12@')
|
|
||||||
if re.search(regex_dewif, line):
|
|
||||||
log.info("input file format detected: dewif")
|
|
||||||
if not self.password:
|
|
||||||
with pynentry.PynEntry() as p:
|
|
||||||
p.description = f"""Data in DEWIF file is encrypted.
|
|
||||||
Please enter a password to decrypt seed.
|
|
||||||
"""
|
|
||||||
p.prompt = 'Passphrase:'
|
|
||||||
try:
|
|
||||||
self.password = p.get_pin()
|
|
||||||
except pynentry.PinEntryCancelled:
|
|
||||||
log.warning('Cancelled! Goodbye.')
|
|
||||||
self._cleanup()
|
|
||||||
exit(1)
|
|
||||||
self.duniterpy = duniterpy.key.SigningKey.from_dewif_file(self.input, self.password)
|
|
||||||
if re.search(regex_p2p, line):
|
|
||||||
log.info("input file format detected: p2p")
|
|
||||||
self.ed25519_secret_libp2p = line
|
|
||||||
self.ed25519_seed_bytes_from_libp2p()
|
|
||||||
self.duniterpy_from_ed25519_seed_bytes()
|
|
||||||
else:
|
|
||||||
raise NotImplementedError('unknown input file format.')
|
|
||||||
else:
|
|
||||||
raise NotImplementedError('empty file.')
|
|
||||||
except Exception as e:
|
|
||||||
log.error(f'Unable to get duniterpy from file {self.input}: {e}')
|
|
||||||
self._cleanup()
|
|
||||||
exit(2)
|
|
||||||
except Exception as e:
|
|
||||||
log.error(f'Unable to get duniterpy from file {self.input}: {e}')
|
|
||||||
self._cleanup()
|
|
||||||
exit(2)
|
|
||||||
log.debug("keygen.duniterpy.seed: %s" % self.duniterpy.seed)
|
|
||||||
|
|
||||||
def duniterpy_from_mnemonic(self):
|
|
||||||
log.debug("keygen.duniterpy_from_mnemonic()")
|
|
||||||
try:
|
|
||||||
scrypt_params = duniterpy.key.scrypt_params.ScryptParams(
|
|
||||||
int(self.config.get('scrypt', 'n')) if self.config.has_option('scrypt', 'n') else 4096,
|
|
||||||
int(self.config.get('scrypt', 'r')) if self.config.has_option('scrypt', 'r') else 16,
|
|
||||||
int(self.config.get('scrypt', 'p')) if self.config.has_option('scrypt', 'p') else 1,
|
|
||||||
int(self.config.get('scrypt', 'sl')) if self.config.has_option('scrypt', 'sl') else 32,
|
|
||||||
)
|
|
||||||
self.duniterpy = duniterpy.key.SigningKey.from_dubp_mnemonic(
|
|
||||||
self.username,
|
|
||||||
scrypt_params
|
|
||||||
)
|
|
||||||
except Exception as e:
|
|
||||||
log.error(f'Unable to get duniterpy from mnemonic: {e}')
|
|
||||||
self._cleanup()
|
|
||||||
exit(2)
|
|
||||||
log.debug("keygen.duniterpy.seed: %s" % self.duniterpy.seed)
|
|
||||||
|
|
||||||
def ed25519_from(self, args):
|
|
||||||
log.debug("keygen.ed25519_from(%s)" % args)
|
|
||||||
if args.gpg:
|
|
||||||
self.ed25519_from_gpg()
|
|
||||||
else:
|
|
||||||
if self.input:
|
|
||||||
self.duniterpy_from_file()
|
|
||||||
else:
|
|
||||||
if self.mnemonic:
|
|
||||||
self.duniterpy_from_mnemonic()
|
|
||||||
else:
|
|
||||||
self.duniterpy_from_credentials()
|
|
||||||
self.ed25519_from_duniterpy()
|
|
||||||
|
|
||||||
def ed25519_from_duniterpy(self):
|
|
||||||
log.debug("keygen.ed25519_from_duniterpy()")
|
|
||||||
try:
|
|
||||||
self.ed25519_seed_bytes_from_duniterpy()
|
|
||||||
self.ed25519_from_seed_bytes()
|
|
||||||
except:
|
|
||||||
log.error(f'Unable to get ed25519 from duniterpy: {e}')
|
|
||||||
self._cleanup()
|
|
||||||
exit(2)
|
|
||||||
|
|
||||||
def ed25519_from_gpg(self):
|
|
||||||
log.debug("keygen.ed25519_from_gpg()")
|
|
||||||
try:
|
|
||||||
self.pgpy_from_gpg()
|
|
||||||
self.ed25519_from_pgpy()
|
|
||||||
except Exception as e:
|
|
||||||
log.error(f'Unable to get ed25519 from pgp: {e}')
|
|
||||||
self._cleanup()
|
|
||||||
exit(2)
|
|
||||||
|
|
||||||
def ed25519_from_pgpy(self):
|
|
||||||
log.debug("keygen.ed25519_from_pgpy()")
|
|
||||||
try:
|
|
||||||
log.debug("keygen.pgpy.fingerprint.keyid=%s" % self.pgpy.fingerprint.keyid)
|
|
||||||
log.debug("keygen.pgpy.is_protected=%s" % self.pgpy.is_protected)
|
|
||||||
if self.pgpy.is_protected:
|
|
||||||
if not self.password:
|
|
||||||
with pynentry.PynEntry() as p:
|
|
||||||
p.description = f"""The exported pgp key id "{self.pgpy.fingerprint.keyid}" of user "{self.username}" is password protected.
|
|
||||||
Please enter the passphrase again to unlock it.
|
|
||||||
"""
|
|
||||||
p.prompt = 'Passphrase:'
|
|
||||||
try:
|
|
||||||
self.password = p.get_pin()
|
|
||||||
except pynentry.PinEntryCancelled:
|
|
||||||
log.warning('Cancelled! Goodbye.')
|
|
||||||
self._cleanup()
|
|
||||||
exit(1)
|
|
||||||
try:
|
|
||||||
with warnings.catch_warnings():
|
|
||||||
# remove CryptographyDeprecationWarning about deprecated
|
|
||||||
# SymmetricKeyAlgorithm IDEA, CAST5 and Blowfish (PGPy v0.5.4)
|
|
||||||
warnings.simplefilter('ignore')
|
|
||||||
with self.pgpy.unlock(self.password):
|
|
||||||
assert self.pgpy.is_unlocked
|
|
||||||
log.debug("keygen.pgpy.is_unlocked=%s" % self.pgpy.is_unlocked)
|
|
||||||
self.ed25519_seed_bytes_from_pgpy()
|
|
||||||
except Exception as e:
|
|
||||||
log.error(f"""Unable to unlock pgp secret key id "{self.pgpy.fingerprint.keyid}" of user "{self.username}": {e}""")
|
|
||||||
self._cleanup()
|
|
||||||
exit(2)
|
|
||||||
else:
|
|
||||||
self.ed25519_seed_bytes_from_pgpy()
|
|
||||||
self.ed25519_from_seed_bytes()
|
|
||||||
except Exception as e:
|
|
||||||
log.error(f'Unable to get ed25519 seed bytes from pgpy: {e}')
|
|
||||||
self._cleanup()
|
|
||||||
exit(2)
|
|
||||||
|
|
||||||
def ed25519_from_seed_bytes(self):
|
|
||||||
log.debug("keygen.ed25519_from_seed_bytes()")
|
|
||||||
try:
|
|
||||||
self.ed25519_public_bytes, self.ed25519_secret_bytes = nacl.bindings.crypto_sign_seed_keypair(self.ed25519_seed_bytes)
|
|
||||||
self.ed25519 = ed25519.Ed25519PrivateKey.from_private_bytes(self.ed25519_seed_bytes)
|
|
||||||
except Exception as e:
|
|
||||||
log.error(f'Unable to get ed25519 from seed bytes: {e}')
|
|
||||||
self._cleanup()
|
|
||||||
exit(2)
|
|
||||||
log.debug("keygen.ed25519_public_bytes=%s" % self.ed25519_public_bytes)
|
|
||||||
log.debug("keygen.ed25519_secret_bytes=%s" % self.ed25519_secret_bytes)
|
|
||||||
|
|
||||||
def ed25519_seed_bytes_from_duniterpy(self):
|
|
||||||
log.debug("keygen.ed25519_seed_bytes_from_duniterpy()")
|
|
||||||
try:
|
|
||||||
self.ed25519_seed_bytes = self.duniterpy.sk[:32]
|
|
||||||
except Exception as e:
|
|
||||||
log.error(f'Unable to get ed25519 seed bytes from duniterpy: {e}')
|
|
||||||
self._cleanup()
|
|
||||||
exit(2)
|
|
||||||
log.debug("keygen.ed25519_seed_bytes=%s" % self.ed25519_seed_bytes)
|
|
||||||
|
|
||||||
def ed25519_seed_bytes_from_jwk(self):
|
|
||||||
log.debug("keygen.ed25519_seed_bytes_from_jwk()")
|
|
||||||
try:
|
|
||||||
self.ed25519_seed_bytes = self.jwk._okp_pri().private_bytes(encoding=serialization.Encoding.Raw, format=serialization.PrivateFormat.Raw, encryption_algorithm=serialization.NoEncryption())
|
|
||||||
except Exception as e:
|
|
||||||
log.error(f'Unable to get ed25519 seed bytes from jwk: {e}')
|
|
||||||
self._cleanup()
|
|
||||||
exit(2)
|
|
||||||
|
|
||||||
def ed25519_seed_bytes_from_pem(self, pem):
|
|
||||||
log.debug("keygen.ed25519_seed_bytes_from_pem()")
|
|
||||||
try:
|
|
||||||
self.ed25519_seed_bytes = serialization.load_pem_private_key(pem, password=None).private_bytes(encoding=serialization.Encoding.Raw, format=serialization.PrivateFormat.Raw, encryption_algorithm=serialization.NoEncryption())
|
|
||||||
except Exception as e:
|
|
||||||
log.error(f'Unable to get ed25519 seed bytes from pem: {e}')
|
|
||||||
self._cleanup()
|
|
||||||
exit(2)
|
|
||||||
|
|
||||||
def ed25519_seed_bytes_from_pgpy(self):
|
|
||||||
log.debug("keygen.ed25519_seed_bytes_from_pgpy()")
|
|
||||||
try:
|
|
||||||
self.pgpy_key_type()
|
|
||||||
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.q=%s" % self.pgpy._key.keymaterial.q)
|
|
||||||
# rsa custom seed: sha256 hash of (p + q), where + is a string concatenation
|
|
||||||
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'):
|
|
||||||
log.debug("keygen.pgpy._key.keymaterial.s=%s" % self.pgpy._key.keymaterial.s)
|
|
||||||
self.ed25519_seed_bytes = self.pgpy._key.keymaterial.s.to_bytes(32, byteorder='big')
|
|
||||||
else:
|
|
||||||
raise NotImplementedError(f"getting seed from pgp key type {self.pgpy_key_type} is not implemented")
|
|
||||||
except Exception as e:
|
|
||||||
log.error(f'Unable to get ed25519 seed bytes from pgpy: {e}')
|
|
||||||
self._cleanup()
|
|
||||||
exit(2)
|
|
||||||
log.debug("keygen.ed25519_seed_bytes=%s" % self.ed25519_seed_bytes)
|
|
||||||
|
|
||||||
def ed25519_seed_bytes_from_libp2p(self):
|
|
||||||
log.debug("keygen.ed25519_seed_bytes_from_libp2p()")
|
|
||||||
try:
|
|
||||||
self.ed25519_seed_bytes = self.ed25519_secret_libp2p.lstrip(b'\x08\x01\x12@')[:32]
|
|
||||||
except Exception as e:
|
|
||||||
log.error(f'Unable to get ed25519 seed bytes from libp2p: {e}')
|
|
||||||
self._cleanup()
|
|
||||||
exit(2)
|
|
||||||
log.debug("keygen.ed25519_seed_bytes=%s" % self.ed25519_seed_bytes)
|
|
||||||
|
|
||||||
def gpg_passphrase_cb(self, uid_hint, passphrase_info, prev_was_bad):
|
|
||||||
log.debug("keygen.gpg_passphrase_cb(%s, %s, %s)" % (uid_hint, passphrase_info, prev_was_bad))
|
|
||||||
return self.password
|
|
||||||
|
|
||||||
def jwk_from_ed25519(self):
|
|
||||||
log.debug("keygen.jwk_from_ed25519()")
|
|
||||||
try:
|
|
||||||
self.jwk = jwk.JWK.from_pyca(self.ed25519)
|
|
||||||
self.ed25519_public_jwk = self.jwk.export_public()
|
|
||||||
self.ed25519_secret_jwk = self.jwk.export_private()
|
|
||||||
except Exception as e:
|
|
||||||
log.error(f'Unable to get jwk from ed25519: {e}')
|
|
||||||
self._cleanup()
|
|
||||||
exit(2)
|
|
||||||
|
|
||||||
def jwk_from_json(self, json):
|
|
||||||
log.debug("keygen.jwk_from_json()")
|
|
||||||
try:
|
|
||||||
self.jwk = jwk.JWK.from_json(json)
|
|
||||||
except Exception as e:
|
|
||||||
log.error(f'Unable to get jwk from json: {e}')
|
|
||||||
self._cleanup()
|
|
||||||
exit(2)
|
|
||||||
|
|
||||||
def pem_pkcs8_from_ed25519(self):
|
|
||||||
log.debug("keygen.pem_pkcs8_from_ed25519()")
|
|
||||||
try:
|
|
||||||
self.ed25519_secret_pem_pkcs8 = self.ed25519.private_bytes(encoding=serialization.Encoding.PEM, format=serialization.PrivateFormat.PKCS8, encryption_algorithm=serialization.NoEncryption()).decode('ascii')
|
|
||||||
except Exception as e:
|
|
||||||
log.error(f'Unable to get pem pkcs8 from ed25519: {e}')
|
|
||||||
self._cleanup()
|
|
||||||
exit(2)
|
|
||||||
log.debug("keygen.ed25519_secret_pem_pkcs8=%s" % self.ed25519_secret_pem_pkcs8)
|
|
||||||
|
|
||||||
def pgpy_from_gpg(self):
|
|
||||||
log.debug("keygen.pgpy_from_gpg()")
|
|
||||||
try:
|
|
||||||
self.gpg_secret_keys = list(self.gpg.keylist(pattern=self.username, secret=True))
|
|
||||||
log.debug("keygen.gpg_secret_keys=%s" % self.gpg_secret_keys)
|
|
||||||
if not self.gpg_secret_keys:
|
|
||||||
log.warning(f"""Unable to find any key matching "{self.username}".""")
|
|
||||||
self._cleanup()
|
|
||||||
exit(1)
|
|
||||||
else:
|
|
||||||
self.gpg_secret_key = self.gpg_secret_keys[0]
|
|
||||||
log.info(f"""Found key id "{self.gpg_secret_key.fpr}" matching "{self.username}".""")
|
|
||||||
log.debug("keygen.gpg_secret_key.expired=%s" % self.gpg_secret_key.expired)
|
|
||||||
log.debug("keygen.gpg_secret_key.fpr=%s" % self.gpg_secret_key.fpr)
|
|
||||||
log.debug("keygen.gpg_secret_key.revoked=%s" % self.gpg_secret_key.revoked)
|
|
||||||
log.debug("keygen.gpg_secret_key.uids=%s" % self.gpg_secret_key.uids)
|
|
||||||
log.debug("keygen.gpg_secret_key.owner_trust=%s" % self.gpg_secret_key.owner_trust)
|
|
||||||
log.debug("keygen.gpg_secret_key.last_update=%s" % self.gpg_secret_key.last_update)
|
|
||||||
if self.password:
|
|
||||||
self.gpg.set_pinentry_mode(gpg.constants.PINENTRY_MODE_LOOPBACK)
|
|
||||||
self.pgp_public_armor = self.gpg.key_export(self.gpg_secret_key.fpr)
|
|
||||||
self.pgp_secret_armor = self.gpg.key_export_secret(self.gpg_secret_key.fpr)
|
|
||||||
log.debug("keygen.pgp_secret_armor=%s" % self.pgp_secret_armor)
|
|
||||||
if not self.pgp_secret_armor:
|
|
||||||
log.error(f"""Unable to export gpg secret key id "{self.gpg_secret_key.fpr}" of user "{self.username}". Please check your password!""")
|
|
||||||
self._cleanup()
|
|
||||||
exit(2)
|
|
||||||
with warnings.catch_warnings():
|
|
||||||
# remove CryptographyDeprecationWarning about deprecated
|
|
||||||
# SymmetricKeyAlgorithm IDEA, CAST5 and Blowfish (PGPy v0.5.4)
|
|
||||||
warnings.simplefilter('ignore')
|
|
||||||
self.pgpy, _ = pgpy.PGPKey.from_blob(self.pgp_secret_armor)
|
|
||||||
except Exception as e:
|
|
||||||
log.error(f'Unable to get pgpy from gpg: {e}')
|
|
||||||
self._cleanup()
|
|
||||||
exit(2)
|
|
||||||
|
|
||||||
def pgpy_key_type(self):
|
|
||||||
log.debug("keygen.pgpy_key_type()")
|
|
||||||
if isinstance(self.pgpy._key.keymaterial, pgpy.packet.fields.RSAPriv):
|
|
||||||
self.pgpy_key_type = 'RSA'
|
|
||||||
elif isinstance(self.pgpy._key.keymaterial, pgpy.packet.fields.DSAPriv):
|
|
||||||
self.pgpy_key_type = 'DSA'
|
|
||||||
elif isinstance(self.pgpy._key.keymaterial, pgpy.packet.fields.ElGPriv):
|
|
||||||
self.pgpy_key_type = 'ElGamal'
|
|
||||||
elif isinstance(self.pgpy._key.keymaterial, pgpy.packet.fields.ECDSAPriv):
|
|
||||||
self.pgpy_key_type = 'ECDSA'
|
|
||||||
elif isinstance(self.pgpy._key.keymaterial, pgpy.packet.fields.EdDSAPriv):
|
|
||||||
self.pgpy_key_type = 'EdDSA'
|
|
||||||
elif isinstance(self.pgpy._key.keymaterial, pgpy.packet.fields.ECDHPriv):
|
|
||||||
self.pgpy_key_type = 'ECDH'
|
|
||||||
else:
|
|
||||||
self.pgpy_key_type = 'undefined'
|
|
||||||
log.debug("keygen.pgpy_key_type=%s" % self.pgpy_key_type)
|
|
||||||
|
|
||||||
def libp2p_from_ed25519(self):
|
|
||||||
# libp2p protobuf version 2
|
|
||||||
log.debug("keygen.libp2p_from_ed25519()")
|
|
||||||
try:
|
|
||||||
# \x00: multihash prefix = id
|
|
||||||
# \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:
|
|
||||||
log.error(f'Unable to get libp2p from ed25519: {e}')
|
|
||||||
self._cleanup()
|
|
||||||
exit(2)
|
|
||||||
log.debug("keygen.ed25519_public_libp2p=%s" % self.ed25519_public_libp2p)
|
|
||||||
log.debug("keygen.ed25519_secret_libp2p=%s" % self.ed25519_secret_libp2p)
|
|
||||||
|
|
||||||
def main(argv=None):
|
|
||||||
if argv is None:
|
|
||||||
argv = sys.argv[1:]
|
|
||||||
return keygen()._cli(argv)
|
|
||||||
|
|
||||||
def version(version=__version__):
|
|
||||||
print("%s v%s" % (sys.argv[0],version))
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
sys.exit(main())
|
|
|
@ -28,13 +28,21 @@ Describe 'Dependency'
|
||||||
The stderr should equal ""
|
The stderr should equal ""
|
||||||
End
|
End
|
||||||
End
|
End
|
||||||
|
Describe 'python3:'
|
||||||
|
It 'is available'
|
||||||
|
When run python3 --help
|
||||||
|
The output should include 'python3'
|
||||||
|
The status should be success
|
||||||
|
The stderr should equal ""
|
||||||
|
End
|
||||||
|
End
|
||||||
End
|
End
|
||||||
|
|
||||||
Describe 'dpgpid'
|
Describe 'dpgpid'
|
||||||
Describe '--help:'
|
Describe '--help:'
|
||||||
It 'prints help'
|
It 'prints help'
|
||||||
When run dpgpid --help
|
When run dpgpid --help
|
||||||
The output should include 'Usage:'
|
The output should include 'usage:'
|
||||||
The status should be success
|
The status should be success
|
||||||
The stderr should equal ""
|
The stderr should equal ""
|
||||||
End
|
End
|
||||||
|
@ -42,7 +50,7 @@ Describe 'dpgpid'
|
||||||
Describe '--version:'
|
Describe '--version:'
|
||||||
It 'prints version'
|
It 'prints version'
|
||||||
When run dpgpid --version
|
When run dpgpid --version
|
||||||
The output should include 'v0.0.1'
|
The output should include 'v0.1.0'
|
||||||
The status should be success
|
The status should be success
|
||||||
The stderr should equal ""
|
The stderr should equal ""
|
||||||
End
|
End
|
||||||
|
|
|
@ -18,8 +18,8 @@ gpg() {
|
||||||
}
|
}
|
||||||
|
|
||||||
keygen() {
|
keygen() {
|
||||||
if [ -x ./keygen.py ]; then
|
if [ -x ./keygen ]; then
|
||||||
GNUPGHOME="${SHELLSPEC_TMPBASE}" ./keygen.py "$@"
|
GNUPGHOME="${SHELLSPEC_TMPBASE}" ./keygen "$@"
|
||||||
elif [ -x ./bin/keygen ]; then
|
elif [ -x ./bin/keygen ]; then
|
||||||
GNUPGHOME="${SHELLSPEC_TMPBASE}" ./bin/keygen "$@"
|
GNUPGHOME="${SHELLSPEC_TMPBASE}" ./bin/keygen "$@"
|
||||||
else
|
else
|
||||||
|
@ -36,14 +36,6 @@ Describe 'Dependency'
|
||||||
The stderr should be present
|
The stderr should be present
|
||||||
End
|
End
|
||||||
End
|
End
|
||||||
Describe 'python3:'
|
|
||||||
It 'is available'
|
|
||||||
When run python3 --help
|
|
||||||
The output should include 'python3'
|
|
||||||
The status should be success
|
|
||||||
The stderr should equal ""
|
|
||||||
End
|
|
||||||
End
|
|
||||||
End
|
End
|
||||||
|
|
||||||
Describe 'keygen'
|
Describe 'keygen'
|
||||||
|
@ -58,217 +50,192 @@ Describe 'keygen'
|
||||||
Describe '--version:'
|
Describe '--version:'
|
||||||
It 'prints version'
|
It 'prints version'
|
||||||
When run keygen --version
|
When run keygen --version
|
||||||
The output should include 'v0.0.5'
|
The output should include 'v0.1.0'
|
||||||
The status should be success
|
The status should be success
|
||||||
The stderr should equal ""
|
The stderr should equal ""
|
||||||
End
|
End
|
||||||
End
|
End
|
||||||
Describe 'username password:'
|
Describe '-p password username:'
|
||||||
It 'prints base58 public key for user "username" and password "password"'
|
It 'prints base58 public key for user "username" and password "password"'
|
||||||
When run keygen username password
|
When run keygen -p password username
|
||||||
The output should include '4YLU1xQ9jzb7LzC6d91VZrYTEKS9N2j93Nnvcee6wxZG'
|
The output should include '4YLU1xQ9jzb7LzC6d91VZrYTEKS9N2j93Nnvcee6wxZG'
|
||||||
The status should be success
|
The status should be success
|
||||||
The stderr should equal ""
|
The stderr should equal ""
|
||||||
End
|
End
|
||||||
End
|
End
|
||||||
Describe '-p username password:'
|
Describe '-p password -s username:'
|
||||||
It 'prints prefixed base58 public key for user "username" and password "password"'
|
|
||||||
When run keygen -p username password
|
|
||||||
The output should include 'pub: 4YLU1xQ9jzb7LzC6d91VZrYTEKS9N2j93Nnvcee6wxZG'
|
|
||||||
The status should be success
|
|
||||||
The stderr should equal ""
|
|
||||||
End
|
|
||||||
End
|
|
||||||
Describe '-s username password:'
|
|
||||||
It 'prints base58 secret key for user "username" and password "password"'
|
It 'prints base58 secret key for user "username" and password "password"'
|
||||||
When run keygen -s username password
|
When run keygen -p password -s username
|
||||||
The output should include 'K5heSX4xGUPtRbxcZh6zbgaKbDv8FeVc9JuSNWtUs7C1oGNKqv7kQJ3DHdouTPzoW4duKKnuLQK8LbHKfN9fkjC'
|
The output should include 'K5heSX4xGUPtRbxcZh6zbgaKbDv8FeVc9JuSNWtUs7C1oGNKqv7kQJ3DHdouTPzoW4duKKnuLQK8LbHKfN9fkjC'
|
||||||
The status should be success
|
The status should be success
|
||||||
The stderr should equal ""
|
The stderr should equal ""
|
||||||
End
|
End
|
||||||
End
|
End
|
||||||
Describe '-ps username password:'
|
Describe '-k -p password username:'
|
||||||
It 'prints prefixed base58 secret key for user "username" and password "password"'
|
|
||||||
When run keygen -ps username password
|
|
||||||
The output should include 'sec: K5heSX4xGUPtRbxcZh6zbgaKbDv8FeVc9JuSNWtUs7C1oGNKqv7kQJ3DHdouTPzoW4duKKnuLQK8LbHKfN9fkjC'
|
|
||||||
The status should be success
|
|
||||||
The stderr should equal ""
|
|
||||||
End
|
|
||||||
End
|
|
||||||
Describe '-k username password:'
|
|
||||||
It 'prints base58 public and secret keys for user "username" and password "password"'
|
It 'prints base58 public and secret keys for user "username" and password "password"'
|
||||||
When run keygen -k username password
|
When run keygen -k -p password username
|
||||||
The output should include '4YLU1xQ9jzb7LzC6d91VZrYTEKS9N2j93Nnvcee6wxZG'
|
The output should include '4YLU1xQ9jzb7LzC6d91VZrYTEKS9N2j93Nnvcee6wxZG'
|
||||||
The output should include 'K5heSX4xGUPtRbxcZh6zbgaKbDv8FeVc9JuSNWtUs7C1oGNKqv7kQJ3DHdouTPzoW4duKKnuLQK8LbHKfN9fkjC'
|
The output should include 'K5heSX4xGUPtRbxcZh6zbgaKbDv8FeVc9JuSNWtUs7C1oGNKqv7kQJ3DHdouTPzoW4duKKnuLQK8LbHKfN9fkjC'
|
||||||
The status should be success
|
The status should be success
|
||||||
The stderr should equal ""
|
The stderr should equal ""
|
||||||
End
|
End
|
||||||
End
|
End
|
||||||
Describe '-pk username password:'
|
Describe '-k -p password -t b36mf username:'
|
||||||
It 'prints prefixed base58 public and secret keys for user "username" and password "password"'
|
It 'prints base36 multiformat public and secret keys for user "username" and password "password"'
|
||||||
When run keygen -pk username password
|
When run keygen -k -p password -t b36mf username
|
||||||
The output should include 'pub: 4YLU1xQ9jzb7LzC6d91VZrYTEKS9N2j93Nnvcee6wxZG'
|
The output should include 'k51qzi5uqu5dhhsbw068pust1xf763zdmyu2mb8rf6ewu2oz3in3a2g6pgtqy3'
|
||||||
The output should include 'sec: K5heSX4xGUPtRbxcZh6zbgaKbDv8FeVc9JuSNWtUs7C1oGNKqv7kQJ3DHdouTPzoW4duKKnuLQK8LbHKfN9fkjC'
|
The output should include 'kmxn88f5mep5chc4tc002gyhtl9vgiluellgje285y2hn5a5kjdvqge7oeb0jryupt1q09w48h2nxg0ofcjco0wjwa824v3p9tvw6us9gdkb'
|
||||||
The status should be success
|
The status should be success
|
||||||
The stderr should equal ""
|
The stderr should equal ""
|
||||||
End
|
End
|
||||||
End
|
End
|
||||||
Describe '-pkt b36mf username password:'
|
Describe '-k -p password -t b58mf username:'
|
||||||
It 'prints prefixed base36 multiformat public and secret keys for user "username" and password "password"'
|
It 'prints base58 multiformat public and secret keys for user "username" and password "password"'
|
||||||
When run keygen -pkt b36mf username password
|
When run keygen -k -p password -t b58mf username
|
||||||
The output should include 'pub: k51qzi5uqu5dhhsbw068pust1xf763zdmyu2mb8rf6ewu2oz3in3a2g6pgtqy3'
|
The output should include 'z5AanNVJCxnJNiidpTZyuYzkQcrHRCyhxMV7Z4KYDV1MYy2ETMrEbUn'
|
||||||
The output should include 'sec: kmxn88f5mep5chc4tc002gyhtl9vgiluellgje285y2hn5a5kjdvqge7oeb0jryupt1q09w48h2nxg0ofcjco0wjwa824v3p9tvw6us9gdkb'
|
The output should include 'z4gg7xjCuszBpvNVcDAmNYVNrZxwXfDDQGoAShWmmQBkWRzZbR8A4ZBpkk4iTj3YSLBxvGZRf1AjCyGDdczhs7tshCsbFK4e'
|
||||||
The status should be success
|
The status should be success
|
||||||
The stderr should equal ""
|
The stderr should equal ""
|
||||||
End
|
End
|
||||||
End
|
End
|
||||||
Describe '-pkt b58mf username password:'
|
Describe '-k -p password -t b58mh username:'
|
||||||
It 'prints prefixed base58 multiformat public and secret keys for user "username" and password "password"'
|
It 'prints base58 multihash public and secret keys for user "username" and password "password"'
|
||||||
When run keygen -pkt b58mf username password
|
When run keygen -k -p password -t b58mh username
|
||||||
The output should include 'pub: z5AanNVJCxnJNiidpTZyuYzkQcrHRCyhxMV7Z4KYDV1MYy2ETMrEbUn'
|
The output should include '12D3KooWDMhdm5yrvtrbkshXFjkqLedHieUnPioczy9wzdnzquHC'
|
||||||
The output should include 'sec: z4gg7xjCuszBpvNVcDAmNYVNrZxwXfDDQGoAShWmmQBkWRzZbR8A4ZBpkk4iTj3YSLBxvGZRf1AjCyGDdczhs7tshCsbFK4e'
|
The output should include '23jhTarm17VAHUwPkHD2Kv5sPfuQrsXSZUzKUrRkP2oP8bgnLjVExhG4AVoayCLxbXN4g2pjVG5qiJRucUtogbj7zGapz'
|
||||||
The status should be success
|
The status should be success
|
||||||
The stderr should equal ""
|
The stderr should equal ""
|
||||||
End
|
End
|
||||||
End
|
End
|
||||||
Describe '-pkt b58mh username password:'
|
Describe '-k -p password -t b64mh username:'
|
||||||
It 'prints prefixed base58 multihash public and secret keys for user "username" and password "password"'
|
It 'prints base64 multihash public and secret keys for user "username" and password "password"'
|
||||||
When run keygen -pkt b58mh username password
|
When run keygen -k -p password -t b64mh username
|
||||||
The output should include 'pub: 12D3KooWDMhdm5yrvtrbkshXFjkqLedHieUnPioczy9wzdnzquHC'
|
The output should include 'ACQIARIgNJoTbvcP+m51+XwxrmWqHaOpI1ZD0USwLjqAmV8Boas='
|
||||||
The output should include 'sec: 23jhTarm17VAHUwPkHD2Kv5sPfuQrsXSZUzKUrRkP2oP8bgnLjVExhG4AVoayCLxbXN4g2pjVG5qiJRucUtogbj7zGapz'
|
The output should include 'CAESQA+XqCWjRqCjNe9oU3QA796bEH+T+rxgyPQ/EkXvE2MvNJoTbvcP+m51+XwxrmWqHaOpI1ZD0USwLjqAmV8Boas='
|
||||||
The status should be success
|
The status should be success
|
||||||
The stderr should equal ""
|
The stderr should equal ""
|
||||||
End
|
End
|
||||||
End
|
End
|
||||||
Describe '-pkt b64mh username password:'
|
Describe '-k -p password -t base58 username:'
|
||||||
It 'prints prefixed base64 multihash public and secret keys for user "username" and password "password"'
|
It 'prints base58 public and secret keys for user "username" and password "password"'
|
||||||
When run keygen -pkt b64mh username password
|
When run keygen -k -p password -t base58 username
|
||||||
The output should include 'pub: ACQIARIgNJoTbvcP+m51+XwxrmWqHaOpI1ZD0USwLjqAmV8Boas='
|
The output should include '4YLU1xQ9jzb7LzC6d91VZrYTEKS9N2j93Nnvcee6wxZG'
|
||||||
The output should include 'sec: CAESQA+XqCWjRqCjNe9oU3QA796bEH+T+rxgyPQ/EkXvE2MvNJoTbvcP+m51+XwxrmWqHaOpI1ZD0USwLjqAmV8Boas='
|
The output should include 'K5heSX4xGUPtRbxcZh6zbgaKbDv8FeVc9JuSNWtUs7C1oGNKqv7kQJ3DHdouTPzoW4duKKnuLQK8LbHKfN9fkjC'
|
||||||
The status should be success
|
The status should be success
|
||||||
The stderr should equal ""
|
The stderr should equal ""
|
||||||
End
|
End
|
||||||
End
|
End
|
||||||
Describe '-pkt base58 username password:'
|
Describe '-k -p password -t base64 username:'
|
||||||
It 'prints prefixed base58 public and secret keys for user "username" and password "password"'
|
It 'prints base64 public and secret keys for user "username" and password "password"'
|
||||||
When run keygen -pkt base58 username password
|
When run keygen -k -p password -t base64 username
|
||||||
The output should include 'pub: 4YLU1xQ9jzb7LzC6d91VZrYTEKS9N2j93Nnvcee6wxZG'
|
The output should include 'NJoTbvcP+m51+XwxrmWqHaOpI1ZD0USwLjqAmV8Boas='
|
||||||
The output should include 'sec: K5heSX4xGUPtRbxcZh6zbgaKbDv8FeVc9JuSNWtUs7C1oGNKqv7kQJ3DHdouTPzoW4duKKnuLQK8LbHKfN9fkjC'
|
The output should include 'D5eoJaNGoKM172hTdADv3psQf5P6vGDI9D8SRe8TYy80mhNu9w/6bnX5fDGuZaodo6kjVkPRRLAuOoCZXwGhqw=='
|
||||||
The status should be success
|
The status should be success
|
||||||
The stderr should equal ""
|
The stderr should equal ""
|
||||||
End
|
End
|
||||||
End
|
End
|
||||||
Describe '-pkt base64 username password:'
|
Describe '-k -p password -t duniter username:'
|
||||||
It 'prints prefixed base64 public and secret keys for user "username" and password "password"'
|
It 'prints duniter public and secret keys for user "username" and password "password"'
|
||||||
When run keygen -pkt base64 username password
|
When run keygen -k -p password -t duniter username
|
||||||
The output should include 'pub: NJoTbvcP+m51+XwxrmWqHaOpI1ZD0USwLjqAmV8Boas='
|
The output should include '4YLU1xQ9jzb7LzC6d91VZrYTEKS9N2j93Nnvcee6wxZG'
|
||||||
The output should include 'sec: D5eoJaNGoKM172hTdADv3psQf5P6vGDI9D8SRe8TYy80mhNu9w/6bnX5fDGuZaodo6kjVkPRRLAuOoCZXwGhqw=='
|
The output should include 'K5heSX4xGUPtRbxcZh6zbgaKbDv8FeVc9JuSNWtUs7C1oGNKqv7kQJ3DHdouTPzoW4duKKnuLQK8LbHKfN9fkjC'
|
||||||
The status should be success
|
The status should be success
|
||||||
The stderr should equal ""
|
The stderr should equal ""
|
||||||
End
|
End
|
||||||
End
|
End
|
||||||
Describe '-pkt duniter username password:'
|
Describe '-k -p password -t ipfs username:'
|
||||||
It 'prints prefixed duniter public and secret keys for user "username" and password "password"'
|
It 'prints ipfs public and secret keys for user "username" and password "password"'
|
||||||
When run keygen -pkt duniter username password
|
When run keygen -k -p password -t ipfs username
|
||||||
The output should include 'pub: 4YLU1xQ9jzb7LzC6d91VZrYTEKS9N2j93Nnvcee6wxZG'
|
The output should include '12D3KooWDMhdm5yrvtrbkshXFjkqLedHieUnPioczy9wzdnzquHC'
|
||||||
The output should include 'sec: K5heSX4xGUPtRbxcZh6zbgaKbDv8FeVc9JuSNWtUs7C1oGNKqv7kQJ3DHdouTPzoW4duKKnuLQK8LbHKfN9fkjC'
|
The output should include 'CAESQA+XqCWjRqCjNe9oU3QA796bEH+T+rxgyPQ/EkXvE2MvNJoTbvcP+m51+XwxrmWqHaOpI1ZD0USwLjqAmV8Boas='
|
||||||
The status should be success
|
The status should be success
|
||||||
The stderr should equal ""
|
The stderr should equal ""
|
||||||
End
|
End
|
||||||
End
|
End
|
||||||
Describe '-pkt ipfs username password:'
|
Describe '-k -p password -t jwk username:'
|
||||||
It 'prints prefixed ipfs public and secret keys for user "username" and password "password"'
|
It 'prints jwk public and secret keys for user "username" and password "password"'
|
||||||
When run keygen -pkt ipfs username password
|
When run keygen -k -p password -t jwk username
|
||||||
The output should include 'PeerID: 12D3KooWDMhdm5yrvtrbkshXFjkqLedHieUnPioczy9wzdnzquHC'
|
The output should include '{"crv":"Ed25519","kty":"OKP","x":"NJoTbvcP-m51-XwxrmWqHaOpI1ZD0USwLjqAmV8Boas"}'
|
||||||
The output should include 'PrivKEY: CAESQA+XqCWjRqCjNe9oU3QA796bEH+T+rxgyPQ/EkXvE2MvNJoTbvcP+m51+XwxrmWqHaOpI1ZD0USwLjqAmV8Boas='
|
The output should include '{"crv":"Ed25519","d":"D5eoJaNGoKM172hTdADv3psQf5P6vGDI9D8SRe8TYy8","kty":"OKP","x":"NJoTbvcP-m51-XwxrmWqHaOpI1ZD0USwLjqAmV8Boas"}'
|
||||||
The status should be success
|
The status should be success
|
||||||
The stderr should equal ""
|
The stderr should equal ""
|
||||||
End
|
End
|
||||||
End
|
End
|
||||||
Describe '-pkt jwk username password:'
|
Describe '-k -m "tongue cute mail ...":'
|
||||||
It 'prints prefixed jwk public and secret keys for user "username" and password "password"'
|
It 'prints base58 public and secret keys for mnemonic "tongue cute mail ..."'
|
||||||
When run keygen -pkt jwk username password
|
When run keygen -k -m "tongue cute mail fossil great frozen same social weasel impact brush kind"
|
||||||
The output should include 'pub: {"crv":"Ed25519","kty":"OKP","x":"NJoTbvcP-m51-XwxrmWqHaOpI1ZD0USwLjqAmV8Boas"}'
|
The output should include '732SSfuwjB7jkt9th1zerGhphs6nknaCBCTozxUcPWPU'
|
||||||
The output should include 'sec: {"crv":"Ed25519","d":"D5eoJaNGoKM172hTdADv3psQf5P6vGDI9D8SRe8TYy8","kty":"OKP","x":"NJoTbvcP-m51-XwxrmWqHaOpI1ZD0USwLjqAmV8Boas"}'
|
The output should include '4NHNg9KSp81nXAN4Gmwx4EZ9bCdahnJ9jozJa1cGj9oDvzx9kCtNSvasqTZVm6VJXBQxyakZ5uZnj8AS6g87kK3x'
|
||||||
The status should be success
|
The status should be success
|
||||||
The stderr should equal ""
|
The stderr should equal ""
|
||||||
End
|
End
|
||||||
End
|
End
|
||||||
Describe '-pkm "tongue cute mail ...":'
|
Describe "-i ${CRED_FILE} -k -v:"
|
||||||
It 'prints prefixed base58 public and secret keys for mnemonic "tongue cute mail ..."'
|
|
||||||
When run keygen -pkm "tongue cute mail fossil great frozen same social weasel impact brush kind"
|
|
||||||
The output should include 'pub: 732SSfuwjB7jkt9th1zerGhphs6nknaCBCTozxUcPWPU'
|
|
||||||
The output should include 'sec: 4NHNg9KSp81nXAN4Gmwx4EZ9bCdahnJ9jozJa1cGj9oDvzx9kCtNSvasqTZVm6VJXBQxyakZ5uZnj8AS6g87kK3x'
|
|
||||||
The status should be success
|
|
||||||
The stderr should equal ""
|
|
||||||
End
|
|
||||||
End
|
|
||||||
Describe "-pki ${CRED_FILE}"
|
|
||||||
printf 'username\npassword\n' > "${CRED_FILE}"
|
printf 'username\npassword\n' > "${CRED_FILE}"
|
||||||
It 'prints prefixed base58 public and secret keys for username and password read from credentials file"'
|
It 'prints base58 public and secret keys for username and password read from credentials file"'
|
||||||
When run keygen -pki "${CRED_FILE}" -v
|
When run keygen -i "${CRED_FILE}" -k -v
|
||||||
The output should include 'pub: 4YLU1xQ9jzb7LzC6d91VZrYTEKS9N2j93Nnvcee6wxZG'
|
The output should include '4YLU1xQ9jzb7LzC6d91VZrYTEKS9N2j93Nnvcee6wxZG'
|
||||||
The output should include 'sec: K5heSX4xGUPtRbxcZh6zbgaKbDv8FeVc9JuSNWtUs7C1oGNKqv7kQJ3DHdouTPzoW4duKKnuLQK8LbHKfN9fkjC'
|
The output should include 'K5heSX4xGUPtRbxcZh6zbgaKbDv8FeVc9JuSNWtUs7C1oGNKqv7kQJ3DHdouTPzoW4duKKnuLQK8LbHKfN9fkjC'
|
||||||
The status should be success
|
The status should be success
|
||||||
The stderr should include 'input file format detected: credentials'
|
The stderr should include 'input file format detected: credentials'
|
||||||
End
|
End
|
||||||
rm -f "${CRED_FILE}"
|
rm -f "${CRED_FILE}"
|
||||||
End
|
End
|
||||||
Describe "-pki ${DUBP_FILE}"
|
Describe "-i ${DUBP_FILE} -k -v:"
|
||||||
printf 'tongue cute mail fossil great frozen same social weasel impact brush kind\n' > "${DUBP_FILE}"
|
printf 'tongue cute mail fossil great frozen same social weasel impact brush kind\n' > "${DUBP_FILE}"
|
||||||
It 'prints prefixed base58 public and secret keys for mnemonic read from dubp file"'
|
It 'prints base58 public and secret keys for mnemonic read from dubp file"'
|
||||||
When run keygen -pki "${DUBP_FILE}" -v
|
When run keygen -i "${DUBP_FILE}" -k -v
|
||||||
The output should include 'pub: 732SSfuwjB7jkt9th1zerGhphs6nknaCBCTozxUcPWPU'
|
The output should include '732SSfuwjB7jkt9th1zerGhphs6nknaCBCTozxUcPWPU'
|
||||||
The output should include 'sec: 4NHNg9KSp81nXAN4Gmwx4EZ9bCdahnJ9jozJa1cGj9oDvzx9kCtNSvasqTZVm6VJXBQxyakZ5uZnj8AS6g87kK3x'
|
The output should include '4NHNg9KSp81nXAN4Gmwx4EZ9bCdahnJ9jozJa1cGj9oDvzx9kCtNSvasqTZVm6VJXBQxyakZ5uZnj8AS6g87kK3x'
|
||||||
The status should be success
|
The status should be success
|
||||||
The stderr should include 'input file format detected: mnemonic'
|
The stderr should include 'input file format detected: mnemonic'
|
||||||
End
|
End
|
||||||
rm -f "${DUBP_FILE}"
|
rm -f "${DUBP_FILE}"
|
||||||
End
|
End
|
||||||
Describe "-f jwk -o ${JWK_FILE} username password:"
|
Describe "-f jwk -o ${JWK_FILE} -p password username:"
|
||||||
rm -f "${JWK_FILE}"
|
rm -f "${JWK_FILE}"
|
||||||
It 'writes secret key to a JWK file for user "username" and password "password"'
|
It 'writes secret key to a JWK file for user "username" and password "password"'
|
||||||
When run keygen -f jwk -o "${JWK_FILE}" username password
|
When run keygen -f jwk -o "${JWK_FILE}" -p password username
|
||||||
The path "${JWK_FILE}" should exist
|
The path "${JWK_FILE}" should exist
|
||||||
The contents of file "${JWK_FILE}" should include '{"crv":"Ed25519","d":"D5eoJaNGoKM172hTdADv3psQf5P6vGDI9D8SRe8TYy8","kty":"OKP","x":"NJoTbvcP-m51-XwxrmWqHaOpI1ZD0USwLjqAmV8Boas"}'
|
The contents of file "${JWK_FILE}" should include '{"crv":"Ed25519","d":"D5eoJaNGoKM172hTdADv3psQf5P6vGDI9D8SRe8TYy8","kty":"OKP","x":"NJoTbvcP-m51-XwxrmWqHaOpI1ZD0USwLjqAmV8Boas"}'
|
||||||
The status should be success
|
The status should be success
|
||||||
The stderr should equal ""
|
The stderr should equal ""
|
||||||
End
|
End
|
||||||
End
|
End
|
||||||
Describe "-pki ${JWK_FILE}:"
|
Describe "-i ${JWK_FILE} -k -v:"
|
||||||
It 'prints prefixed base58 public and secret keys for ed25519 key read from JWK file"'
|
It 'prints base58 public and secret keys for ed25519 key read from JWK file"'
|
||||||
When run keygen -pki "${JWK_FILE}" -v
|
When run keygen -i "${JWK_FILE}" -k -v
|
||||||
The output should include 'pub: 4YLU1xQ9jzb7LzC6d91VZrYTEKS9N2j93Nnvcee6wxZG'
|
The output should include '4YLU1xQ9jzb7LzC6d91VZrYTEKS9N2j93Nnvcee6wxZG'
|
||||||
The output should include 'sec: K5heSX4xGUPtRbxcZh6zbgaKbDv8FeVc9JuSNWtUs7C1oGNKqv7kQJ3DHdouTPzoW4duKKnuLQK8LbHKfN9fkjC'
|
The output should include 'K5heSX4xGUPtRbxcZh6zbgaKbDv8FeVc9JuSNWtUs7C1oGNKqv7kQJ3DHdouTPzoW4duKKnuLQK8LbHKfN9fkjC'
|
||||||
The status should be success
|
The status should be success
|
||||||
The stderr should include 'input file format detected: jwk'
|
The stderr should include 'input file format detected: jwk'
|
||||||
End
|
End
|
||||||
rm -f "${JWK_FILE}"
|
rm -f "${JWK_FILE}"
|
||||||
End
|
End
|
||||||
Describe "-f nacl -o ${NACL_FILE} username password:"
|
Describe "-f nacl -o ${NACL_FILE} -p password username:"
|
||||||
rm -f "${NACL_FILE}"
|
rm -f "${NACL_FILE}"
|
||||||
It 'writes secret key to a libnacl file for user "username" and password "password"'
|
It 'writes secret key to a libnacl file for user "username" and password "password"'
|
||||||
When run keygen -f nacl -o "${NACL_FILE}" username password
|
When run keygen -f nacl -o "${NACL_FILE}" -p password username
|
||||||
The path "${NACL_FILE}" should exist
|
The path "${NACL_FILE}" should exist
|
||||||
The contents of file "${NACL_FILE}" should include '{"priv": "0f97a825a346a0a335ef68537400efde9b107f93fabc60c8f43f1245ef13632f349a136ef70ffa6e75f97c31ae65aa1da3a9235643d144b02e3a80995f01a1ab", "verify": "349a136ef70ffa6e75f97c31ae65aa1da3a9235643d144b02e3a80995f01a1ab", "sign": "0f97a825a346a0a335ef68537400efde9b107f93fabc60c8f43f1245ef13632f"}'
|
The contents of file "${NACL_FILE}" should include '{"priv": "0f97a825a346a0a335ef68537400efde9b107f93fabc60c8f43f1245ef13632f349a136ef70ffa6e75f97c31ae65aa1da3a9235643d144b02e3a80995f01a1ab", "verify": "349a136ef70ffa6e75f97c31ae65aa1da3a9235643d144b02e3a80995f01a1ab", "sign": "0f97a825a346a0a335ef68537400efde9b107f93fabc60c8f43f1245ef13632f"}'
|
||||||
The status should be success
|
The status should be success
|
||||||
The stderr should equal ""
|
The stderr should equal ""
|
||||||
End
|
End
|
||||||
End
|
End
|
||||||
Describe "-pki ${NACL_FILE}:"
|
Describe "-i ${NACL_FILE} -k -v:"
|
||||||
It 'prints prefixed base58 public and secret keys for ed25519 key read from libnacl file"'
|
It 'prints base58 public and secret keys for ed25519 key read from libnacl file"'
|
||||||
When run keygen -pki "${NACL_FILE}" -v
|
When run keygen -i "${NACL_FILE}" -k -v
|
||||||
The output should include 'pub: 4YLU1xQ9jzb7LzC6d91VZrYTEKS9N2j93Nnvcee6wxZG'
|
The output should include '4YLU1xQ9jzb7LzC6d91VZrYTEKS9N2j93Nnvcee6wxZG'
|
||||||
The output should include 'sec: K5heSX4xGUPtRbxcZh6zbgaKbDv8FeVc9JuSNWtUs7C1oGNKqv7kQJ3DHdouTPzoW4duKKnuLQK8LbHKfN9fkjC'
|
The output should include 'K5heSX4xGUPtRbxcZh6zbgaKbDv8FeVc9JuSNWtUs7C1oGNKqv7kQJ3DHdouTPzoW4duKKnuLQK8LbHKfN9fkjC'
|
||||||
The status should be success
|
The status should be success
|
||||||
The stderr should include 'input file format detected: nacl'
|
The stderr should include 'input file format detected: nacl'
|
||||||
End
|
End
|
||||||
rm -f "${NACL_FILE}"
|
rm -f "${NACL_FILE}"
|
||||||
End
|
End
|
||||||
Describe "-f ewif -o ${EWIF_FILE} username password:"
|
Describe "-f ewif -o ${EWIF_FILE} -p password username:"
|
||||||
rm -f "${EWIF_FILE}"
|
rm -f "${EWIF_FILE}"
|
||||||
It 'writes encrypted secret key to a ewif file for user "username" and password "password"'
|
It 'writes encrypted secret key to an EWIF file for user "username" and password "password"'
|
||||||
When run keygen -f ewif -o "${EWIF_FILE}" username password
|
When run keygen -f ewif -o "${EWIF_FILE}" -p password username
|
||||||
The path "${EWIF_FILE}" should exist
|
The path "${EWIF_FILE}" should exist
|
||||||
The contents of file "${EWIF_FILE}" should include 'Type: EWIF'
|
The contents of file "${EWIF_FILE}" should include 'Type: EWIF'
|
||||||
The contents of file "${EWIF_FILE}" should include 'Version: 1'
|
The contents of file "${EWIF_FILE}" should include 'Version: 1'
|
||||||
|
@ -277,20 +244,20 @@ Describe 'keygen'
|
||||||
The stderr should equal ""
|
The stderr should equal ""
|
||||||
End
|
End
|
||||||
End
|
End
|
||||||
Describe "-pki ${EWIF_FILE}:"
|
Describe "-i ${EWIF_FILE} -k -p password -v:"
|
||||||
It 'prints prefixed base58 public and secret keys for ed25519 key read from EWIF file"'
|
It 'prints base58 public and secret keys for ed25519 key read from EWIF file encrypted with password "password"'
|
||||||
When run keygen -pki "${EWIF_FILE}" -v username password
|
When run keygen -i "${EWIF_FILE}" -k -p password -v username
|
||||||
The output should include 'pub: 4YLU1xQ9jzb7LzC6d91VZrYTEKS9N2j93Nnvcee6wxZG'
|
The output should include '4YLU1xQ9jzb7LzC6d91VZrYTEKS9N2j93Nnvcee6wxZG'
|
||||||
The output should include 'sec: K5heSX4xGUPtRbxcZh6zbgaKbDv8FeVc9JuSNWtUs7C1oGNKqv7kQJ3DHdouTPzoW4duKKnuLQK8LbHKfN9fkjC'
|
The output should include 'K5heSX4xGUPtRbxcZh6zbgaKbDv8FeVc9JuSNWtUs7C1oGNKqv7kQJ3DHdouTPzoW4duKKnuLQK8LbHKfN9fkjC'
|
||||||
The status should be success
|
The status should be success
|
||||||
The stderr should include 'input file format detected: ewif'
|
The stderr should include 'input file format detected: ewif'
|
||||||
End
|
End
|
||||||
rm -f "${EWIF_FILE}"
|
rm -f "${EWIF_FILE}"
|
||||||
End
|
End
|
||||||
Describe "-o ${PEM_FILE} username password:"
|
Describe "-o ${PEM_FILE} -p password username:"
|
||||||
rm -f "${PEM_FILE}"
|
rm -f "${PEM_FILE}"
|
||||||
It 'writes pkcs8 secret key to a pem file for user "username" and password "password"'
|
It 'writes pkcs8 secret key to a pem file for user "username" and password "password"'
|
||||||
When run keygen -o "${PEM_FILE}" -t ipfs username password
|
When run keygen -o "${PEM_FILE}" -p password username
|
||||||
The path "${PEM_FILE}" should exist
|
The path "${PEM_FILE}" should exist
|
||||||
The contents of file "${PEM_FILE}" should include '-----BEGIN PRIVATE KEY-----'
|
The contents of file "${PEM_FILE}" should include '-----BEGIN PRIVATE KEY-----'
|
||||||
The contents of file "${PEM_FILE}" should include 'MC4CAQAwBQYDK2VwBCIEIA+XqCWjRqCjNe9oU3QA796bEH+T+rxgyPQ/EkXvE2Mv'
|
The contents of file "${PEM_FILE}" should include 'MC4CAQAwBQYDK2VwBCIEIA+XqCWjRqCjNe9oU3QA796bEH+T+rxgyPQ/EkXvE2Mv'
|
||||||
|
@ -299,10 +266,10 @@ Describe 'keygen'
|
||||||
The stderr should equal ""
|
The stderr should equal ""
|
||||||
End
|
End
|
||||||
End
|
End
|
||||||
Describe "-f pem -o ${PEM_FILE} username password:"
|
Describe "-f pem -o ${PEM_FILE} -p password username:"
|
||||||
rm -f "${PEM_FILE}"
|
rm -f "${PEM_FILE}"
|
||||||
It 'writes pkcs8 secret key to a pem file for user "username" and password "password"'
|
It 'writes pkcs8 secret key to a pem file for user "username" and password "password"'
|
||||||
When run keygen -f pem -o "${PEM_FILE}" -t ipfs username password
|
When run keygen -f pem -o "${PEM_FILE}" -p password username
|
||||||
The path "${PEM_FILE}" should exist
|
The path "${PEM_FILE}" should exist
|
||||||
The contents of file "${PEM_FILE}" should include '-----BEGIN PRIVATE KEY-----'
|
The contents of file "${PEM_FILE}" should include '-----BEGIN PRIVATE KEY-----'
|
||||||
The contents of file "${PEM_FILE}" should include 'MC4CAQAwBQYDK2VwBCIEIA+XqCWjRqCjNe9oU3QA796bEH+T+rxgyPQ/EkXvE2Mv'
|
The contents of file "${PEM_FILE}" should include 'MC4CAQAwBQYDK2VwBCIEIA+XqCWjRqCjNe9oU3QA796bEH+T+rxgyPQ/EkXvE2Mv'
|
||||||
|
@ -311,17 +278,17 @@ Describe 'keygen'
|
||||||
The stderr should equal ""
|
The stderr should equal ""
|
||||||
End
|
End
|
||||||
End
|
End
|
||||||
Describe "-pki ${PEM_FILE}:"
|
Describe "-i ${PEM_FILE} -k -v:"
|
||||||
It 'prints prefixed base58 public and secret keys for ed25519 key read from pkcs8 pem file"'
|
It 'prints base58 public and secret keys for ed25519 key read from pkcs8 pem file"'
|
||||||
When run keygen -pki "${PEM_FILE}" -v
|
When run keygen -i "${PEM_FILE}" -k -v
|
||||||
The output should include 'pub: 4YLU1xQ9jzb7LzC6d91VZrYTEKS9N2j93Nnvcee6wxZG'
|
The output should include '4YLU1xQ9jzb7LzC6d91VZrYTEKS9N2j93Nnvcee6wxZG'
|
||||||
The output should include 'sec: K5heSX4xGUPtRbxcZh6zbgaKbDv8FeVc9JuSNWtUs7C1oGNKqv7kQJ3DHdouTPzoW4duKKnuLQK8LbHKfN9fkjC'
|
The output should include 'K5heSX4xGUPtRbxcZh6zbgaKbDv8FeVc9JuSNWtUs7C1oGNKqv7kQJ3DHdouTPzoW4duKKnuLQK8LbHKfN9fkjC'
|
||||||
The status should be success
|
The status should be success
|
||||||
The stderr should include 'input file format detected: pem'
|
The stderr should include 'input file format detected: pem'
|
||||||
End
|
End
|
||||||
rm -f "${PEM_FILE}"
|
rm -f "${PEM_FILE}"
|
||||||
End
|
End
|
||||||
Describe "-f p2p -o ${P2P_FILE} username password:"
|
Describe "-f p2p -o ${P2P_FILE} -p password username:"
|
||||||
rm -f "${P2P_FILE}"
|
rm -f "${P2P_FILE}"
|
||||||
It 'writes libp2p secret key to a p2p file for user "username" and password "password"'
|
It 'writes libp2p secret key to a p2p file for user "username" and password "password"'
|
||||||
decode_p2p() {
|
decode_p2p() {
|
||||||
|
@ -331,7 +298,7 @@ Describe 'keygen'
|
||||||
! 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 p2p -o "${P2P_FILE}" username password
|
When run keygen -f p2p -o "${P2P_FILE}" -p password username
|
||||||
The path "${P2P_FILE}" should exist
|
The path "${P2P_FILE}" should exist
|
||||||
The result of function decode_p2p should include '080112400f97a825a346a0a335ef68537400efde9b107f93fabc60c8f43f'
|
The result of function decode_p2p should include '080112400f97a825a346a0a335ef68537400efde9b107f93fabc60c8f43f'
|
||||||
The result of function decode_p2p should include '1245ef13632f349a136ef70ffa6e75f97c31ae65aa1da3a9235643d144b0'
|
The result of function decode_p2p should include '1245ef13632f349a136ef70ffa6e75f97c31ae65aa1da3a9235643d144b0'
|
||||||
|
@ -340,20 +307,20 @@ Describe 'keygen'
|
||||||
The stderr should equal ""
|
The stderr should equal ""
|
||||||
End
|
End
|
||||||
End
|
End
|
||||||
Describe "-pki ${P2P_FILE}:"
|
Describe "-i ${P2P_FILE} -k -v:"
|
||||||
It 'prints prefixed base58 public and secret keys for ed25519 key read from p2p file"'
|
It 'prints base58 public and secret keys for ed25519 key read from p2p file"'
|
||||||
When run keygen -pki "${P2P_FILE}" -v
|
When run keygen -i "${P2P_FILE}" -k -v
|
||||||
The output should include 'pub: 4YLU1xQ9jzb7LzC6d91VZrYTEKS9N2j93Nnvcee6wxZG'
|
The output should include '4YLU1xQ9jzb7LzC6d91VZrYTEKS9N2j93Nnvcee6wxZG'
|
||||||
The output should include 'sec: K5heSX4xGUPtRbxcZh6zbgaKbDv8FeVc9JuSNWtUs7C1oGNKqv7kQJ3DHdouTPzoW4duKKnuLQK8LbHKfN9fkjC'
|
The output should include 'K5heSX4xGUPtRbxcZh6zbgaKbDv8FeVc9JuSNWtUs7C1oGNKqv7kQJ3DHdouTPzoW4duKKnuLQK8LbHKfN9fkjC'
|
||||||
The status should be success
|
The status should be success
|
||||||
The stderr should include 'input file format detected: p2p'
|
The stderr should include 'input file format detected: p2p'
|
||||||
End
|
End
|
||||||
rm -f "${P2P_FILE}"
|
rm -f "${P2P_FILE}"
|
||||||
End
|
End
|
||||||
Describe "-f pubsec -o ${PUBSEC_FILE} username password:"
|
Describe "-f pubsec -o ${PUBSEC_FILE} -p password username:"
|
||||||
rm -f "${PUBSEC_FILE}"
|
rm -f "${PUBSEC_FILE}"
|
||||||
It 'writes base58 public and secret keys to a pubsec file for user "username" and password "password"'
|
It 'writes base58 public and secret keys to a pubsec file for user "username" and password "password"'
|
||||||
When run keygen -f pubsec -o "${PUBSEC_FILE}" username password
|
When run keygen -f pubsec -o "${PUBSEC_FILE}" -p password username
|
||||||
The path "${PUBSEC_FILE}" should exist
|
The path "${PUBSEC_FILE}" should exist
|
||||||
The contents of file "${PUBSEC_FILE}" should include 'Type: PubSec'
|
The contents of file "${PUBSEC_FILE}" should include 'Type: PubSec'
|
||||||
The contents of file "${PUBSEC_FILE}" should include 'Version: 1'
|
The contents of file "${PUBSEC_FILE}" should include 'Version: 1'
|
||||||
|
@ -363,10 +330,10 @@ Describe 'keygen'
|
||||||
The stderr should equal ""
|
The stderr should equal ""
|
||||||
End
|
End
|
||||||
End
|
End
|
||||||
Describe "-o ${PUBSEC_FILE} -t duniter username password:"
|
Describe "-o ${PUBSEC_FILE} -p password -t duniter username:"
|
||||||
rm -f "${PUBSEC_FILE}"
|
rm -f "${PUBSEC_FILE}"
|
||||||
It 'writes duniter public and secret keys to a pubsec file for user "username" and password "password"'
|
It 'writes duniter public and secret keys to a pubsec file for user "username" and password "password"'
|
||||||
When run keygen -o "${PUBSEC_FILE}" -t duniter username password
|
When run keygen -o "${PUBSEC_FILE}" -p password -t duniter username
|
||||||
The path "${PUBSEC_FILE}" should exist
|
The path "${PUBSEC_FILE}" should exist
|
||||||
The contents of file "${PUBSEC_FILE}" should include 'Type: PubSec'
|
The contents of file "${PUBSEC_FILE}" should include 'Type: PubSec'
|
||||||
The contents of file "${PUBSEC_FILE}" should include 'Version: 1'
|
The contents of file "${PUBSEC_FILE}" should include 'Version: 1'
|
||||||
|
@ -376,51 +343,51 @@ Describe 'keygen'
|
||||||
The stderr should equal ""
|
The stderr should equal ""
|
||||||
End
|
End
|
||||||
End
|
End
|
||||||
Describe "-pki ${PUBSEC_FILE} -t ipfs:"
|
Describe "-i ${PUBSEC_FILE} -k -t ipfs -v:"
|
||||||
It 'prints prefixed ipfs public and secret keys for base58 keys read in a pubsec file'
|
It 'prints ipfs public and secret keys for base58 keys read in a pubsec file'
|
||||||
When run keygen -pki "${PUBSEC_FILE}" -t ipfs -v
|
When run keygen -i "${PUBSEC_FILE}" -k -t ipfs -v
|
||||||
The output should include 'PeerID: 12D3KooWDMhdm5yrvtrbkshXFjkqLedHieUnPioczy9wzdnzquHC'
|
The output should include '12D3KooWDMhdm5yrvtrbkshXFjkqLedHieUnPioczy9wzdnzquHC'
|
||||||
The output should include 'PrivKEY: CAESQA+XqCWjRqCjNe9oU3QA796bEH+T+rxgyPQ/EkXvE2MvNJoTbvcP+m51+XwxrmWqHaOpI1ZD0USwLjqAmV8Boas='
|
The output should include 'CAESQA+XqCWjRqCjNe9oU3QA796bEH+T+rxgyPQ/EkXvE2MvNJoTbvcP+m51+XwxrmWqHaOpI1ZD0USwLjqAmV8Boas='
|
||||||
The status should be success
|
The status should be success
|
||||||
The stderr should include 'input file format detected: pubsec'
|
The stderr should include 'input file format detected: pubsec'
|
||||||
End
|
End
|
||||||
rm -f "${PUBSEC_FILE}"
|
rm -f "${PUBSEC_FILE}"
|
||||||
End
|
End
|
||||||
Describe "-pki ${SSB_FILE}:"
|
Describe "-i ${SSB_FILE} -k -v:"
|
||||||
printf '{ "curve": "ed25519", "public": "cFVodZoKwLcmXbM6UeASdl8+7+Uo8PNOuFnlcqk7qUc=.ed25519", "private": "lUqlXYxjkM0/ljtGnwoM0CfP6ORA2DKZnzsQ4dJ1tKJwVWh1mgrAtyZdszpR4BJ2Xz7v5Sjw8064WeVyqTupRw==.ed25519", "id": "@cFVodZoKwLcmXbM6UeASdl8+7+Uo8PNOuFnlcqk7qUc=.ed25519" }\n' > "${SSB_FILE}"
|
printf '{ "curve": "ed25519", "public": "cFVodZoKwLcmXbM6UeASdl8+7+Uo8PNOuFnlcqk7qUc=.ed25519", "private": "lUqlXYxjkM0/ljtGnwoM0CfP6ORA2DKZnzsQ4dJ1tKJwVWh1mgrAtyZdszpR4BJ2Xz7v5Sjw8064WeVyqTupRw==.ed25519", "id": "@cFVodZoKwLcmXbM6UeASdl8+7+Uo8PNOuFnlcqk7qUc=.ed25519" }\n' > "${SSB_FILE}"
|
||||||
It 'prints prefixed base58 public and secret keys for ed25519 key read from ssb file"'
|
It 'prints prefixed base58 public and secret keys for ed25519 key read from ssb file"'
|
||||||
When run keygen -pki "${SSB_FILE}" -v
|
When run keygen -i "${SSB_FILE}" -k -v
|
||||||
The output should include 'pub: 8ZWCTFBUczYRucyvTgJL6oefj28u243LYU4ZjYKn4XDG'
|
The output should include '8ZWCTFBUczYRucyvTgJL6oefj28u243LYU4ZjYKn4XDG'
|
||||||
The output should include 'sec: 3z7vcMHQhnVPTEEaFQ5gxn2NHkmJsFHkZ4W2aoAvt3Jt5ZYhFV1M6NEkm7Lr75pEF61oSkQVsaih9cQWBP2JmbVQ'
|
The output should include '3z7vcMHQhnVPTEEaFQ5gxn2NHkmJsFHkZ4W2aoAvt3Jt5ZYhFV1M6NEkm7Lr75pEF61oSkQVsaih9cQWBP2JmbVQ'
|
||||||
The status should be success
|
The status should be success
|
||||||
The stderr should include 'input file format detected: ssb'
|
The stderr should include 'input file format detected: ssb'
|
||||||
End
|
End
|
||||||
rm -f "${SSB_FILE}"
|
rm -f "${SSB_FILE}"
|
||||||
End
|
End
|
||||||
Describe "-f seed -o ${SEED_FILE} username password:"
|
Describe "-f seed -o ${SEED_FILE} -p password username:"
|
||||||
rm -f "${SEED_FILE}"
|
rm -f "${SEED_FILE}"
|
||||||
It 'writes encoded secret key to a wif file for user "username" and password "password"'
|
It 'writes encoded secret key to a wif file for user "username" and password "password"'
|
||||||
When run keygen -f seed -o "${SEED_FILE}" username password
|
When run keygen -f seed -o "${SEED_FILE}" -p password username
|
||||||
The path "${SEED_FILE}" should exist
|
The path "${SEED_FILE}" should exist
|
||||||
The contents of file "${SEED_FILE}" should include '0f97a825a346a0a335ef68537400efde9b107f93fabc60c8f43f1245ef13632f'
|
The contents of file "${SEED_FILE}" should include '0f97a825a346a0a335ef68537400efde9b107f93fabc60c8f43f1245ef13632f'
|
||||||
The status should be success
|
The status should be success
|
||||||
The stderr should equal ""
|
The stderr should equal ""
|
||||||
End
|
End
|
||||||
End
|
End
|
||||||
Describe "-pki ${SEED_FILE}:"
|
Describe "-i ${SEED_FILE} -k -v:"
|
||||||
It 'prints prefixed base58 public and secret keys for ed25519 key read from seed file"'
|
It 'prints base58 public and secret keys for ed25519 key read from seed file"'
|
||||||
When run keygen -pki "${SEED_FILE}" -v
|
When run keygen -i "${SEED_FILE}" -k -v
|
||||||
The output should include 'pub: 4YLU1xQ9jzb7LzC6d91VZrYTEKS9N2j93Nnvcee6wxZG'
|
The output should include '4YLU1xQ9jzb7LzC6d91VZrYTEKS9N2j93Nnvcee6wxZG'
|
||||||
The output should include 'sec: K5heSX4xGUPtRbxcZh6zbgaKbDv8FeVc9JuSNWtUs7C1oGNKqv7kQJ3DHdouTPzoW4duKKnuLQK8LbHKfN9fkjC'
|
The output should include 'K5heSX4xGUPtRbxcZh6zbgaKbDv8FeVc9JuSNWtUs7C1oGNKqv7kQJ3DHdouTPzoW4duKKnuLQK8LbHKfN9fkjC'
|
||||||
The status should be success
|
The status should be success
|
||||||
The stderr should include 'input file format detected: seed'
|
The stderr should include 'input file format detected: seed'
|
||||||
End
|
End
|
||||||
rm -f "${SEED_FILE}"
|
rm -f "${SEED_FILE}"
|
||||||
End
|
End
|
||||||
Describe "-f wif -o ${WIF_FILE} username password:"
|
Describe "-f wif -o ${WIF_FILE} -p password username:"
|
||||||
rm -f "${WIF_FILE}"
|
rm -f "${WIF_FILE}"
|
||||||
It 'writes encoded secret key to a wif file for user "username" and password "password"'
|
It 'writes encoded secret key to a wif file for user "username" and password "password"'
|
||||||
When run keygen -f wif -o "${WIF_FILE}" username password
|
When run keygen -f wif -o "${WIF_FILE}" -p password username
|
||||||
The path "${WIF_FILE}" should exist
|
The path "${WIF_FILE}" should exist
|
||||||
The contents of file "${WIF_FILE}" should include 'Type: WIF'
|
The contents of file "${WIF_FILE}" should include 'Type: WIF'
|
||||||
The contents of file "${WIF_FILE}" should include 'Version: 1'
|
The contents of file "${WIF_FILE}" should include 'Version: 1'
|
||||||
|
@ -429,62 +396,62 @@ Describe 'keygen'
|
||||||
The stderr should equal ""
|
The stderr should equal ""
|
||||||
End
|
End
|
||||||
End
|
End
|
||||||
Describe "-pki ${WIF_FILE}:"
|
Describe "-i ${WIF_FILE} -k -v:"
|
||||||
It 'prints prefixed base58 public and secret keys for ed25519 key read from WIF file"'
|
It 'prints base58 public and secret keys for ed25519 key read from WIF file"'
|
||||||
When run keygen -pki "${WIF_FILE}" -v
|
When run keygen -i "${WIF_FILE}" -k -v
|
||||||
The output should include 'pub: 4YLU1xQ9jzb7LzC6d91VZrYTEKS9N2j93Nnvcee6wxZG'
|
The output should include '4YLU1xQ9jzb7LzC6d91VZrYTEKS9N2j93Nnvcee6wxZG'
|
||||||
The output should include 'sec: K5heSX4xGUPtRbxcZh6zbgaKbDv8FeVc9JuSNWtUs7C1oGNKqv7kQJ3DHdouTPzoW4duKKnuLQK8LbHKfN9fkjC'
|
The output should include 'K5heSX4xGUPtRbxcZh6zbgaKbDv8FeVc9JuSNWtUs7C1oGNKqv7kQJ3DHdouTPzoW4duKKnuLQK8LbHKfN9fkjC'
|
||||||
The status should be success
|
The status should be success
|
||||||
The stderr should include 'input file format detected: wif'
|
The stderr should include 'input file format detected: wif'
|
||||||
End
|
End
|
||||||
rm -f "${WIF_FILE}"
|
rm -f "${WIF_FILE}"
|
||||||
End
|
End
|
||||||
Describe '-t gpg username password birthday:'
|
Describe '-b 0 -p password -t gpg username:'
|
||||||
It 'creates a password protected gpg key for user "username"'
|
It 'creates a password protected gpg key for user "username"'
|
||||||
Skip "You should implement it !"
|
Skip "You should implement it !"
|
||||||
When run keygen -t pgp username password birthday
|
When run keygen -b 0 -p password -t pgp username
|
||||||
The status should be success
|
The status should be success
|
||||||
End
|
End
|
||||||
End
|
End
|
||||||
Describe '-pkg username:'
|
Describe '-g -k username:'
|
||||||
gpg --batch --import --quiet specs/username.asc
|
gpg --batch --import --quiet specs/username.asc
|
||||||
It 'prints prefixed base58 public and secret keys for ed25519 gpg key matching uid "username"'
|
It 'prints base58 public and secret keys for ed25519 gpg key matching uid "username"'
|
||||||
When run keygen -pkg username
|
When run keygen -g -k username
|
||||||
The output should include 'pub: 2g5UL2zhkn5i7oNYDpWo3fBuWvRYVU1AbMtdVmnGzPNv'
|
The output should include '2g5UL2zhkn5i7oNYDpWo3fBuWvRYVU1AbMtdVmnGzPNv'
|
||||||
The output should include 'sec: 5WtYFfA26nTfG496gAKhkrLYUMMnwXexmE1E8Q7PvtQEyscHfirsdMzW34zDp7WEkt3exNEVwoG4ajZYrm62wpi2'
|
The output should include '5WtYFfA26nTfG496gAKhkrLYUMMnwXexmE1E8Q7PvtQEyscHfirsdMzW34zDp7WEkt3exNEVwoG4ajZYrm62wpi2'
|
||||||
The status should be success
|
The status should be success
|
||||||
The stderr should equal ""
|
The stderr should equal ""
|
||||||
End
|
End
|
||||||
gpg --batch --delete-secret-and-public-key --yes 4D1CDB77E91FFCD81B10F9A7079E5BF4721944FB
|
gpg --batch --delete-secret-and-public-key --yes 4D1CDB77E91FFCD81B10F9A7079E5BF4721944FB
|
||||||
End
|
End
|
||||||
Describe '-pkg username@protected password:'
|
Describe '-g -k -p password username@protected:'
|
||||||
gpg --batch --import --quiet specs/username_protected.asc
|
gpg --batch --import --quiet specs/username_protected.asc
|
||||||
It 'prints prefixed public and secret keys for ed25519 gpg key matching uid "username@protected" and locked with password "password"'
|
It 'prints public and secret keys for ed25519 gpg key matching uid "username@protected" and locked with password "password"'
|
||||||
When run keygen -pkg username@protected password
|
When run keygen -g -k -p password username@protected
|
||||||
The output should include 'pub: C1cRu7yb5rZhsmRHQkeZxusAhtYYJypcnXpY3HycEKsU'
|
The output should include 'C1cRu7yb5rZhsmRHQkeZxusAhtYYJypcnXpY3HycEKsU'
|
||||||
The output should include 'sec: VWaEdDroSCoagJDsBnDNUtXJtKAJYdqL6XKNiomz8DtiyF44FvpiMmhidXt2j8HhDBKPZ67xBGcZPnj4Myk6cB8'
|
The output should include 'VWaEdDroSCoagJDsBnDNUtXJtKAJYdqL6XKNiomz8DtiyF44FvpiMmhidXt2j8HhDBKPZ67xBGcZPnj4Myk6cB8'
|
||||||
The status should be success
|
The status should be success
|
||||||
The stderr should equal ""
|
The stderr should equal ""
|
||||||
End
|
End
|
||||||
gpg --batch --delete-secret-and-public-key --yes 6AF574897D4979B7956AC31B6222A29CBC31A087
|
gpg --batch --delete-secret-and-public-key --yes 6AF574897D4979B7956AC31B6222A29CBC31A087
|
||||||
End
|
End
|
||||||
Describe '-pkg usersame:'
|
Describe '-g -k usersame:'
|
||||||
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 base58 public and secret keys for rsa gpg key matching uid "usersame"'
|
||||||
When run keygen -pkg usersame
|
When run keygen -g -k usersame
|
||||||
The output should include 'pub: EGdSY9fKom7MnvHALNQU7LUoEEE2sju5ntL9eRXJ5tTM'
|
The output should include 'EGdSY9fKom7MnvHALNQU7LUoEEE2sju5ntL9eRXJ5tTM'
|
||||||
The output should include 'sec: 4jPG9MH9LVA7HhcfFs41pXVjxDQLdgu3Mtc64Ph6U3vUMNWfJqTBdFFaviq5r6zJC8PpWUiaUhjVnYAa2E9UrFTZ'
|
The output should include '4jPG9MH9LVA7HhcfFs41pXVjxDQLdgu3Mtc64Ph6U3vUMNWfJqTBdFFaviq5r6zJC8PpWUiaUhjVnYAa2E9UrFTZ'
|
||||||
The status should be success
|
The status should be success
|
||||||
The stderr should equal ""
|
The stderr should equal ""
|
||||||
End
|
End
|
||||||
gpg --batch --delete-secret-and-public-key --yes 845E099CFD17FD07346F9D26CAB2E65557C656DF
|
gpg --batch --delete-secret-and-public-key --yes 845E099CFD17FD07346F9D26CAB2E65557C656DF
|
||||||
End
|
End
|
||||||
Describe '-pkg usersame@protected password:'
|
Describe '-g -k -p password usersame@protected:'
|
||||||
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 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 -g -k -p password usersame@protected
|
||||||
The output should include 'pub: 6KNNPBxkMYnccYvpePBKDewZ3JiQnmWA4e7QSsvZUzLM'
|
The output should include '6KNNPBxkMYnccYvpePBKDewZ3JiQnmWA4e7QSsvZUzLM'
|
||||||
The output should include 'sec: 4q4SM9qoWc2eLtfYWs7K9hb7oSCNjCLc8U6ELNrScteVGVnSBP4YMDM5V8RPsHURqCqP5ndPkqGoB74cmRxfJro7'
|
The output should include '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