Apparition du G1VOEUX

This commit is contained in:
fred 2022-08-18 16:14:43 +02:00
parent c3fa3363c0
commit d2d7f568a1
8 changed files with 756 additions and 0 deletions

161
G1VOEUX.sh Executable file
View File

@ -0,0 +1,161 @@
#!/bin/bash
################################################################################
# Author: Fred (support@qo-op.com)
# Version: 0.1
# License: AGPL-3.0 (https://choosealicense.com/licenses/agpl-3.0/)
################################################################################
MY_PATH="`dirname \"$0\"`" # relative
MY_PATH="`( cd \"$MY_PATH\" && pwd )`" # absolutized and normalized
ME="${0##*/}"
################################################################################
# Create and print VOEUX.
# Attributed to a place shared through Astroport Ŋ1 confidence network IPFS layer
# PARAMETRES
# Promesse de virement du MONTANT, le nom du joueur PLAYER et sa G1PUB.
################################################################################
MONTANT="$1"
PLAYER="$2"
G1PUB="$3"
QRTW="$4" # Nombre de QR + TW5 à créer
[[ $MONTANT == "" ]] && MONTANT="_?_"
[[ $PLAYER == "" ]] && PLAYER=$(cat ~/.zen/game/players/.current/.player 2>/dev/null)
PSEUDO=$(cat ~/.zen/game/players/.current/.pseudo 2>/dev/null)
[[ $PLAYER == "" ]] && echo "Second paramètre PLAYER manquant" && exit 1
[[ $G1PUB == "" ]] && G1PUB=$(cat ~/.zen/game/players/.current/.g1pub 2>/dev/null)
[[ $G1PUB == "" ]] && echo "Troisième paramètre G1PUB manquant" && exit 1
[[ $QRTW == "" ]] && QRTW=1
ASTRONAUTENS=$(ipfs key list -l | grep -w "${PLAYER}" | cut -d ' ' -f 1)
[[ $ASTRONAUTENS == "" ]] && echo "ASTRONAUTE manquant" && exit 1
echo "Bienvenue $PSEUDO ($PLAYER) : $G1PUB"
echo "Astronaute Ŋ1 : http://127.0.0.1:8080/ipns/$ASTRONAUTENS"
echo
# BACKING UP IPNS
rm -f ~/.zen/tmp/index.html
ipfs --timeout 5s get -o ~/.zen/tmp/index.html /ipns/$ASTRONAUTENS
if [ ! -f ~/.zen/tmp/index.html ]; then
echo "ERROR IPNS TIMEOUT"
TW=$(ipfs add -Hq ~/.zen/game/players/$PLAYER/ipfs/moa/index.html | tail -n 1)
ipfs name publish --key=$G1PUB /ipfs/$TW
else
cp ~/.zen/tmp/index.html ~/.zen/game/players/$PLAYER/ipfs/moa/index.html
fi
# CREATION DE $QRTW BILLETS DE $MONTANT DU
boucle=0;
while [ $boucle -lt $QRTW ]
do
boucle=$((boucle+1))
SALT=$(${MY_PATH}/diceware.sh 3 | xargs)
PEPPER=$(${MY_PATH}/diceware.sh 1 | xargs)
echo "Entrez un Mot titre pour ce Voeu"
read PEPPER
echo "# CREATION CLEF DE VOEUX"
${MY_PATH}/keygen -t duniter -o ~/.zen/tmp/qrtw.dunikey "$SALT" "$PEPPER"
WISHKEY=$(cat ~/.zen/tmp/qrtw.dunikey | grep "pub:" | cut -d ' ' -f 2)
echo "# NOUVEAU VOEU ASTRONAUTE"
mkdir -p ~/.zen/game/players/$PLAYER/voeux/$WISHKEY/
${MY_PATH}/keygen -t ipfs -o ~/.zen/game/players/$PLAYER/voeux/$WISHKEY/qrtw.ipfskey "$SALT" "$PEPPER"
VOEUXNS=$(ipfs key import $WISHKEY -f pem-pkcs8-cleartext ~/.zen/game/players/$PLAYER/voeux/$WISHKEY/qrtw.ipfskey)
# CRYPTO BUG. TODO use natools to protect and share key with Ŋ1 only ;)
echo "# CREATION WORLD UPGRADE DATABASE"
MOATS=$(date -u +"%Y%m%d%H%M%S%4N")
mkdir -p ~/.zen/game/world/$WISHKEY/
echo $PEPPER > ~/.zen/game/world/$WISHKEY/.pepper
echo "# CREATION TW"
# ipfs cat /ipfs/bafybeigqut7yod32gbu3ykruu2zzegzi4i7zc7tjggxvcwkilw5s44vuqi > ~/.zen/Astroport.ONE/templates/twdefault.html
cp ~/.zen/Astroport.ONE/templates/twdefault.html ~/.zen/game/world/$WISHKEY/index.html
# PERSONNALISATION
sed -i "s~_BIRTHDATE_~${MOATS}~g" ~/.zen/game/world/$WISHKEY/index.html
sed -i "s~_PSEUDO_~${PSEUDO}~g" ~/.zen/game/world/$WISHKEY/index.html
sed -i "s~_PLAYER_~${PLAYER}~g" ~/.zen/game/world/$WISHKEY/index.html
sed -i "s~_G1PUB_~${G1PUB}~g" ~/.zen/game/world/$WISHKEY/index.html
sed -i "s~_WISHKEY_~${WISHKEY}~g" ~/.zen/game/world/$WISHKEY/index.html
sed -i "s~_NUMBER_~${SALT}~g" ~/.zen/game/world/$WISHKEY/index.html
sed -i "s~_SECRET_~${PEPPER}~g" ~/.zen/game/world/$WISHKEY/index.html
# IPNS KEY is WISHKEY / VOEUXNS
sed -i "s~_MEDIAKEY_~${WISHKEY}~g" ~/.zen/game/world/$WISHKEY/index.html
sed -i "s~k2k4r8naeti1ny2hsk3a0ziwz22urwiu633hauluwopf4vwjk4x68qgk~${VOEUXNS}~g" ~/.zen/game/world/$WISHKEY/index.html
# ASTROPORT RELAY
sed -i "s~ipfs.infura.io~tube.copylaradio.com~g" ~/.zen/game/world/$WISHKEY/index.html
echo "# CREATION QR CODE"
HOST="$(hostname).local"
qrencode -s 6 -o "$HOME/.zen/game/world/$WISHKEY/QR.WISHLINK.png" "http://$HOST:8080/ipns/$VOEUXNS"
qrencode -s 6 -o "$HOME/.zen/game/world/$WISHKEY/QR.ASTROLINK.png" "http://$HOST:8080/ipns/$ASTRONAUTENS"
qrencode -s 6 -o "$HOME/.zen/game/world/$WISHKEY/QR.G1ASTRO.png" "$G1PUB"
qrencode -s 6 -o "$HOME/.zen/game/world/$WISHKEY/QR.G1WISH.png" "$WISHKEY"
qrencode -s 6 -o "$HOME/.zen/game/world/$WISHKEY/QR.IPNS.png" "/ipns/$VOEUXNS"
# Bricolage avec node tiddlywiki (TODO add tiddler with command line)
#
cd ~/.zen/game/world/$WISHKEY
tiddlywiki $WISHKEY --load ~/.zen/game/world/$WISHKEY/index.html --savewikifolder ./tw/
cd -
# PREMIER TYPE
convert $HOME/.zen/game/world/$WISHKEY/QR.WISHLINK.png -resize 300 /tmp/QR.png
convert ${MY_PATH}/images/logoastro.png -resize 220 /tmp/ASTROLOGO.png
convert ${MY_PATH}/images/logojeu.png -resize 260 /tmp/MIZLOGO.png
composite -compose Over -gravity NorthWest -geometry +350+10 /tmp/ASTROLOGO.png ${MY_PATH}/images/Brother_600x400.png /tmp/astroport.png
composite -compose Over -gravity NorthWest -geometry +0+0 /tmp/QR.png /tmp/astroport.png /tmp/one.png
convert -gravity northwest -pointsize 35 -fill black -draw "text 320,250 \"$PSEUDO\"" /tmp/one.png /tmp/hop.png
convert -gravity northwest -pointsize 30 -fill black -draw "text 20,320 \"$PEPPER\"" /tmp/hop.png /tmp/pseudo.png
convert -gravity northwest -pointsize 30 -fill black -draw "text 320,300 \"$SALT\"" /tmp/pseudo.png /tmp/salt.png
convert -gravity northwest -pointsize 40 -fill black -draw "text 320,350 \"$PEPPER\"" /tmp/salt.png /tmp/player.png
# SECOND TYPE
convert $HOME/.zen/game/world/$WISHKEY/QR.G1WISH.png -resize 300 /tmp/G1.png
convert $HOME/.zen/game/world/$WISHKEY/QR.IPNS.png -resize 300 /tmp/IPNS.png
composite -compose Over -gravity NorthWest -geometry +300+0 /tmp/G1.png ${MY_PATH}/images/Brother_600x400.png /tmp/astroport.png
composite -compose Over -gravity NorthWest -geometry +0+0 /tmp/IPNS.png /tmp/astroport.png /tmp/one.png
composite -compose Over -gravity NorthWest -geometry +320+280 /tmp/MIZLOGO.png /tmp/one.png /tmp/two.png
convert -gravity northwest -pointsize 50 -fill black -draw "text 30,300 \"Ğ1 RÊVE\"" /tmp/play.png /tmp/voeu.png
convert -gravity northwest -pointsize 28 -fill black -draw "text 32,350 \"$PEPPER\"" /tmp/two.png /tmp/play.png
# IMAGE IPFS
IREVE=$(ipfs add -Hq /tmp/voeu.png | tail -n 1)
sed -i "s~bafybeidhghlcx3zdzdah2pzddhoicywmydintj4mosgtygr6f2dlfwmg7a~${IREVE}~g" ~/.zen/game/world/$WISHKEY/index.html
# PRINTING
LP=$(ls /dev/usb/lp* | head -n1)
[[ ! $LP ]] && echo "NO PRINTER FOUND - Brother QL700 validated" # && exit 1
echo "IMPRESSION VOEU"
brother_ql_create --model QL-700 --label-size 62 /tmp/player.png > /tmp/toprint.bin 2>/dev/null
sudo brother_ql_print /tmp/toprint.bin $LP
brother_ql_create --model QL-700 --label-size 62 /tmp/voeu.png > /tmp/toprint.bin 2>/dev/null
sudo brother_ql_print /tmp/toprint.bin $LP
# PUBLISHING
echo "## ${PLAYER} RECORDING YOU WISH INTO BLOCKCHAIN"
echo "ipfs add -rHq ~/.zen/game/world/$WISHKEY/
ipfs name publish --key=${WISHKEY} /ipfs/\$IPUSH"
IPUSH=$(ipfs add -rHq ~/.zen/game/world/$WISHKEY/ | tail -n 1)
echo $IPUSH > ~/.zen/game/world/$WISHKEY/.chain # Contains last IPFS backup PLAYER KEY
echo $MOATS > ~/.zen/game/world/$WISHKEY/.moats
ipfs name publish --key=${WISHKEY} /ipfs/$IPUSH 2>/dev/null
echo "CAPSULE A REVE $PEPPER : http://127.0.0.1:8080/ipns/$VOEUXNS"
echo "PRESSEZ ENTRER POUR CONTINUER"
read
done
exit 0

22
crypto.proto Normal file
View File

@ -0,0 +1,22 @@
syntax = "proto2";
package crypto.pb;
option go_package = "github.com/libp2p/go-libp2p-core/crypto/pb";
enum KeyType {
RSA = 0;
Ed25519 = 1;
Secp256k1 = 2;
ECDSA = 3;
}
message PublicKey {
required KeyType Type = 1;
required bytes Data = 2;
}
message PrivateKey {
required KeyType Type = 1;
required bytes Data = 2;
}

162
crypto_pb2.py Normal file
View File

@ -0,0 +1,162 @@
# 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)

BIN
images/Brother_600x100.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 825 B

BIN
images/Brother_600x300.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

BIN
images/Brother_600x400.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

BIN
images/Brother_600x600.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

411
keygen Executable file
View File

@ -0,0 +1,411 @@
#!/usr/bin/env python3
# link: https://git.p2p.legal/aya/dpgpid/
# desc: generate ed25519 keys suitable for duniter or ipfs
# 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 base58
import base64
import configparser
import crypto_pb2
import cryptography.hazmat.primitives.asymmetric.ed25519 as ed25519
from cryptography.hazmat.primitives import serialization
import duniterpy.key
import gpg
import nacl.bindings
import nacl.encoding
import pgpy
import logging as log
import os
import re
import struct
import sys
import time
__version__='0.0.1'
class keygen:
def __init__(self):
self.parser = argparse.ArgumentParser()
self.parser.add_argument(
"-d",
"--debug",
action="store_true",
help="show debug informations",
)
self.parser.add_argument(
"-i",
"--input",
dest="input",
default=None,
help="read public and secret keys in pubsec format from file INPUT",
)
self.parser.add_argument(
"-g",
"--gpg",
action="store_true",
help="use gpg key from user id matched by username option as input",
)
self.parser.add_argument(
"-o",
"--output",
dest="output",
default=None,
help="write public and secret keys to file OUTPUT",
)
self.parser.add_argument(
"-q",
"--quiet",
action="store_true",
help="show only errors",
)
self.parser.add_argument(
"-t",
"--type",
dest="type",
default="ipfs",
help="output key type : [ duniter | ipfs ]",
)
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("def keygen._check_args(self, args)")
log.debug("self.username=%s" % self.username)
log.debug("self.password=%s" % self.password)
if self.input is None:
if self.password is None:
if self.username is None or args.gpg is False:
self.parser.error(f"keygen requires an input file or username and password args")
def _invalid_type(self):
log.debug("def keygen._invalid_type(self)")
self.parser.error(f"type: {self.type} is not valid.")
def _load_config(self):
log.debug("def keygen._load_config(self)")
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 base58_from_ed25519(self):
log.debug("def keygen.base58_from_ed25519(self)")
self.base58_public_key = base58.b58encode(self.ed25519_public_bytes).decode('ascii')
self.base58_secret_key = base58.b58encode(self.ed25519_secret_bytes).decode('ascii')
log.debug("self.base58_public_key=%s" % self.base58_public_key)
log.debug("self.base58_secret_key=%s" % self.base58_secret_key)
def base58_from_pubsec(self):
log.debug("def keygen.base58_from_pubsec(self)")
for line in open(self.input, "r"):
if re.search("pub", line):
self.base58_public_key = line.replace('\n','').split(': ')[1]
elif re.search("sec", line):
self.base58_secret_key = line.replace('\n','').split(': ')[1]
def do_duniter(self):
log.debug("def keygen.do_duniter(self)")
self.base58_from_ed25519()
if self.output is None:
print("pub: %s" % self.base58_public_key)
print("sec: %s" % self.base58_secret_key)
else:
with open(self.output, "w") as fh:
fh.write(f"""Type: PubSec
Version: 1
pub: {self.base58_public_key}
sec: {self.base58_secret_key}
"""
)
os.chmod(self.output, 0o600)
def do_ipfs(self):
log.debug("def keygen.do_ipfs(self)")
self.ipfs_from_ed25519()
if self.output is None:
print("PeerID: %s" % self.ipfs_peerid)
print("PrivKEY: %s" % self.ipfs_privkey)
else:
# with open(self.output, "wb") as fh:
# fh.write(self.ipfs_libp2p_protobuf_key)
with open(self.output, "w") as fh:
fh.write(self.ed25519_secret_pem_pkcs8)
os.chmod(self.output, 0o600)
def duniterpy_from_salt_and_password(self):
log.debug("def keygen.duniterpy_from_salt_and_password(self)")
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_credentials(
self.username,
self.password,
scrypt_params
)
def ed25519(self, args):
log.debug("def keygen.ed25519(self, args)")
if args.gpg is True:
self.ed25519_from_gpg()
elif self.input is None:
self.duniterpy_from_salt_and_password()
self.ed25519_from_duniterpy()
else:
self.base58_from_pubsec()
self.ed25519_from_base58()
def ed25519_from_base58(self):
log.debug("def keygen.ed25519_from_base58(self)")
self.ed25519_public_bytes = base58.b58decode(self.base58_public_key)
self.ed25519_secret_bytes = base58.b58decode(self.base58_secret_key)
log.debug("self.ed25519_public_bytes=%s" % self.ed25519_public_bytes)
log.debug("self.ed25519_secret_bytes=%s" % self.ed25519_secret_bytes)
def ed25519_from_duniterpy(self):
log.debug("def keygen.ed25519_from_duniterpy(self)")
self.ed25519_public_bytes = base58.b58decode(self.duniterpy.pubkey)
self.ed25519_secret_bytes = self.duniterpy.sk
log.debug("self.ed25519_public_bytes=%s" % self.ed25519_public_bytes)
log.debug("self.ed25519_secret_bytes=%s" % self.ed25519_secret_bytes)
def ed25519_from_gpg(self):
log.debug("def keygen.ed25519_from_gpg(self)")
self.gpg_pubkeys = list(self.gpg.keylist(pattern=self.username, secret=False))
self.gpg_seckeys = list(self.gpg.keylist(pattern=self.username, secret=True))
log.debug("self.gpg_pubkeys=%s" % self.gpg_pubkeys)
log.debug("self.gpg_seckeys=%s" % self.gpg_seckeys)
self.gpg_seckey = self.gpg_seckeys[0]
log.debug("self.gpg_seckey.fpr=%s" % self.gpg_seckey.fpr)
log.debug("self.gpg_seckey.key=%s" % self.gpg_seckey.__repr__)
self.armored_pgp_public_key = self.gpg.key_export(self.gpg_seckey.fpr)
self.armored_pgp_secret_key = self.gpg.key_export_secret(self.gpg_seckey.fpr)
log.debug("self.armored_pgp_public_key=%s" % self.armored_pgp_public_key)
log.debug("self.armored_pgp_secret_key=%s" % self.armored_pgp_secret_key)
self.pgpy, _ = pgpy.PGPKey.from_blob(self.armored_pgp_secret_key)
log.debug("self.pgpy.fingerprint.keyid=%s" % self.pgpy.fingerprint.keyid)
self.ed25519_from_pgpy()
def ed25519_from_pgpy(self):
log.debug("def keygen.ed25519_from_pgpy(self)")
self.pgpy_key_seed()
self.ed25519_public_bytes, self.ed25519_secret_bytes = nacl.bindings.crypto_sign_seed_keypair(self.pgpy_key_seed)
log.debug("self.ed25519_public_bytes=%s" % self.ed25519_public_bytes)
log.debug("self.ed25519_secret_bytes=%s" % self.ed25519_secret_bytes)
def ipfs_from_ed25519(self):
log.debug("def keygen.ipfs_from_ed25519(self)")
# PeerID
ipfs_pid = base58.b58encode(b'\x00$\x08\x01\x12 ' + self.ed25519_public_bytes)
self.ipfs_peerid = ipfs_pid.decode('ascii')
log.debug("self.ipfs_peerid=%s" % self.ipfs_peerid)
# PrivKey
pkey = crypto_pb2.PrivateKey()
pkey.Type = crypto_pb2.KeyType.Ed25519
pkey.Data = self.ed25519_secret_bytes
self.ipfs_privkey = base64.b64encode(pkey.SerializeToString()).decode('ascii')
log.debug("self.ipfs_privkey=%s" % self.ipfs_privkey)
# libp2p-protobuf-cleartext format for ipfs key import
self.ipfs_libp2p_protobuf_key = pkey.SerializeToString()
# pem-pkcs8-cleartext format for ipfs key import
self.pem_pkcs8_from_ed25519()
def pem_pkcs8_from_ed25519(self):
log.debug("def keygen.pem_pkcs8_from_ed25519(self)")
self.ed25519_secret_pem_pkcs8 = ed25519.Ed25519PrivateKey.from_private_bytes(self.ed25519_secret_bytes[:32]).private_bytes(encoding=serialization.Encoding.PEM, format=serialization.PrivateFormat.PKCS8, encryption_algorithm=serialization.NoEncryption()).decode('ascii')
log.debug("self.ed25519_secret_pem_pkcs8=%s" % self.ed25519_secret_pem_pkcs8)
def pgpy_key_flags(self):
log.debug("def keygen.pgpy_key_flags(self)")
flags = []
strs = {pgpy.constants.KeyFlags.Certify : 'C',
pgpy.constants.KeyFlags.Sign : 'S',
pgpy.constants.KeyFlags.EncryptCommunications : 'E',
pgpy.constants.KeyFlags.Authentication : 'A'}
for sig in self.pgpy.self_signatures:
if not sig.is_expired:
flags += sig.key_flags
self.pgpy_key_flags = "".join(strs.get(flag, '') for flag in flags)
def pgpy_key_seed(self):
log.debug("def keygen.pgpy_key_seed(self)")
self.pgpy_key_type()
# todo : unlock password protected key
# assert self.pgpy.is_unlocked
if self.pgpy_key_type == 'RSA':
log.debug("self.pgpy._key.keymaterial.p=%s" % self.pgpy._key.keymaterial.p)
log.debug("self.pgpy._key.keymaterial.q=%s" % self.pgpy._key.keymaterial.q)
# custom seed: use sha256 hash of (p + q)
self.pgpy_key_seed = nacl.bindings.crypto_hash_sha256(long_to_bytes(self.pgpy._key.keymaterial.p + self.pgpy._key.keymaterial.q))
p = long_to_bytes(self.pgpy._key.keymaterial.p)
q = long_to_bytes(self.pgpy._key.keymaterial.q)
self.pgpy_key_value = "".join([f"{c:02x}" for c in p]) + "".join([f"{c:02x}" for c in q])
self.pgpy_key_size = (len(p) + len(q)) * 8
log.debug("self.pgpy_key_seed=%s" % self.pgpy_key_seed)
log.debug("self.pgpy_key_value=%s" % self.pgpy_key_value)
log.debug("self.pgpy_key_size=%s" % self.pgpy_key_size)
log.debug("self.pgpy._key.keymaterial.encbytes=%s" % self.pgpy._key.keymaterial.encbytes)
elif self.pgpy_key_type in ('ECDSA', 'EdDSA', 'ECDH'):
log.debug("self.pgpy._key.keymaterial.s=%s" % self.pgpy._key.keymaterial.s)
self.pgpy_key_seed = long_to_bytes(self.pgpy._key.keymaterial.s)
self.pgpy_key_value = "".join([f"{c:02x}" for c in self.pgpy_key_seed])
self.pgpy_key_size = len(self.pgpy_key_seed)*8
log.debug("self.pgpy_key_seed=%s" % self.pgpy_key_seed)
log.debug("self.pgpy_key_value=%s" % self.pgpy_key_value)
log.debug("self.pgpy_key_size=%s" % self.pgpy_key_size)
else:
raise NotImplementedError(f"Get seed from {self.pgpy_key_type} key is not supported")
def pgpy_key_type(self):
log.debug("def keygen.pgpy_key_type(self)")
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("self.pgpy_key_type=%s" % self.pgpy_key_type)
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, homedir=GNUPGHOME)
self.gpg = gpg.Context(armor=True, offline=True)
self.ed25519(args)
method = getattr(self, f'do_{self.type}', self._invalid_type)
return method()
# long_to_bytes comes from PyCrypto, which is released into Public Domain
# https://github.com/dlitz/pycrypto/blob/master/lib/Crypto/Util/number.py
def bytes_to_long(s):
"""bytes_to_long(string) : long
Convert a byte string to a long integer.
This is (essentially) the inverse of long_to_bytes().
"""
acc = 0
unpack = struct.unpack
length = len(s)
if length % 4:
extra = (4 - length % 4)
s = b'\000' * extra + s
length = length + extra
for i in range(0, length, 4):
acc = (acc << 32) + unpack('>I', s[i:i+4])[0]
return acc
def long_to_bytes(n, blocksize=0):
"""long_to_bytes(n:long, blocksize:int) : string
Convert a long integer to a byte string.
If optional blocksize is given and greater than zero, pad the front of the
byte string with binary zeros so that the length is a multiple of
blocksize.
"""
# after much testing, this algorithm was deemed to be the fastest
s = b''
n = int(n)
pack = struct.pack
while n > 0:
s = pack('>I', n & 0xffffffff) + s
n = n >> 32
# strip off leading zeros
for i in range(len(s)):
if s[i] != b'\000'[0]:
break
else:
# only happens when n == 0
s = b'\000'
i = 0
s = s[i:]
# add back some pad bytes. this could be done more efficiently w.r.t. the
# de-padding being done above, but sigh...
if blocksize > 0 and len(s) % blocksize:
s = (blocksize - len(s) % blocksize) * b'\000' + s
return s
def main(argv=None):
if argv is None:
argv = sys.argv[1:]
cli = keygen()
return cli.run(argv)
def version(version=__version__):
print("%s v%s" % (sys.argv[0],version))
if __name__ == "__main__":
sys.exit(main())