From 3b59580084dd03a2561885a519b9f28790e6fb77 Mon Sep 17 00:00:00 2001 From: poka Date: Wed, 4 Nov 2020 15:16:03 +0100 Subject: [PATCH] Add options meca; fusion message files in one; update natools; add .env --- .env.template | 4 + .gitignore | 1 + helloworld/title | 1 - natools.py | 130 +++++++++++++++++++++++++++++---- sendmsg.sh | 33 ++++++--- helloworld/content => test.txt | 3 +- 6 files changed, 145 insertions(+), 27 deletions(-) create mode 100644 .env.template create mode 100644 .gitignore delete mode 100644 helloworld/title rename helloworld/content => test.txt (81%) diff --git a/.env.template b/.env.template new file mode 100644 index 0000000..7cf8ceb --- /dev/null +++ b/.env.template @@ -0,0 +1,4 @@ +issuer="" # Clé publique Ḡ1 de l'émetteur du message +recipient="" # Clé publique Ḡ1 du destinataire du message +dunikey="" # La clé privé Ḡ1 de l'émetteur, générable par Cesium au format PubSec +pod="https://g1.data.duniter.fr" # Noeud Cecium+ utilisé pour l'envoi du message diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4c49bd7 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.env diff --git a/helloworld/title b/helloworld/title deleted file mode 100644 index a974651..0000000 --- a/helloworld/title +++ /dev/null @@ -1 +0,0 @@ -Hello Astro ! diff --git a/natools.py b/natools.py index a4af840..c69cb22 100755 --- a/natools.py +++ b/natools.py @@ -17,9 +17,9 @@ along with this program. If not, see . """ -__version__ = "1.0" +__version__ = "1.2.2" -import os, sys, duniterpy.key, libnacl.sign, base58, base64 +import os, sys, duniterpy.key, libnacl, libnacl.sign, base58, base64, getpass def getargv(arg:str, default:str="", n:int=1, args:list=sys.argv) -> str: if arg in args and len(args) > args.index(arg)+n: @@ -53,17 +53,73 @@ def sign(data, privkey): def verify(data, pubkey): try: + ret = libnacl.sign.Verifier(duniterpy.key.PublicKey(pubkey).hex_pk()).verify(data) sys.stderr.write("Signature OK!\n") - return libnacl.sign.Verifier(duniterpy.key.PublicKey(pubkey).hex_pk()).verify(data) + return ret except ValueError: sys.stderr.write("Bad signature!\n") exit(1) -def get_privkey(privkey_path, pubsec): - if pubsec: +def get_privkey(privkey_path, privkey_format): + if privkey_format == "pubsec": + if privkey_path == "*": + privkey_path = "privkey.pubsec" return duniterpy.key.SigningKey.from_pubsec_file(privkey_path) - else: + + elif privkey_format == "cred": + if privkey_path == "*": + privkey_path = "-" + if privkey_path == "-": + return duniterpy.key.SigningKey.from_credentials(getpass.getpass("Password: "), getpass.getpass("Salt: ")) + else: + return duniterpy.key.SigningKey.from_credentials_file(privkey_path) + + elif privkey_format == "seedh": + if privkey_path == "*": + privkey_path = "authfile.seedhex" return duniterpy.key.SigningKey.from_seedhex(read_data(privkey_path, False)) + + elif privkey_format == "wif": + if privkey_path == "*": + privkey_path = "authfile.wif" + return duniterpy.key.SigningKey.from_wif_or_ewif_file(privkey_path) + + elif privkey_format == "wifh": + if privkey_path == "*": + privkey_path = "authfile.wif" + return duniterpy.key.SigningKey.from_wif_or_ewif_hex(privkey_path) + + elif privkey_format == "ssb": + if privkey_path == "*": + privkey_path = "secret" + return duniterpy.key.SigningKey.from_ssb_file(privkey_path) + + elif privkey_format == "key": + if privkey_path == "*": + privkey_path = "authfile.key" + return duniterpy.key.SigningKey.from_private_key(privkey_path) + + print("Error: unknown privkey format") + +def fill_pubkey(pubkey, length=32): + while pubkey[0] == 0: + pubkey = pubkey[1:] + return b"\x00"*(length-len(pubkey)) + pubkey + +def pubkey_checksum(pubkey, length=32, clength=3): + return base58.b58encode(libnacl.crypto_hash_sha256(libnacl.crypto_hash_sha256(fill_pubkey(base58.b58decode(pubkey), length)))).decode()[:clength] + +# returns (pubkey:bytes|None, deprecated_length:bool) +def check_pubkey(pubkey): + if ":" in pubkey: + parts = pubkey.split(":") + if len(parts[1]) < 3 or len(parts[1]) > 32: + return (None, False) + for i in range(32, 0, -1): + if pubkey_checksum(parts[0], i, len(parts[1])) == parts[1]: + return (parts[0], i < 32) + return (None, False) + return (pubkey, False) fmt = { "raw": lambda data: data, @@ -84,18 +140,23 @@ Commands: decrypt Decrypt data sign Sign data verify Verify data + pubkey Display pubkey + pk Display b58 pubkey shorthand Options: + -c Display pubkey checksum + -f Private key format (default: cred) + key cred pubsec seedh ssb wif wifh -i Input file path (default: -) - -k Privkey file path (default: authfile.key) - --pubsec Use pub/sec format for -p - -p Pubkey (base58) - -o Output file path (default: -) + -k Privkey file path (* for auto) (default: *) --noinc Do not include msg after signature + -o Output file path (default: -) -O Output format: raw 16 32 58 64 64u 85 (default: raw) + -p Pubkey (base58) --help Show help --version Show version + --debug Debug mode (display full errors) Note: "-" means stdin or stdout. """) @@ -110,23 +171,37 @@ if __name__ == "__main__": print(__version__) exit() + privkey_format = getargv("-f", "cred") data_path = getargv("-i", "-") - privkey_path = getargv("-k", "authfile.key") - pubsec = "--pubsec" in sys.argv + privkey_path = getargv("-k", "*") pubkey = getargv("-p") result_path = getargv("-o", "-") output_format = getargv("-O", "raw") + if pubkey: + pubkey, len_deprecated = check_pubkey(pubkey) + if not pubkey: + print("Invalid pubkey checksum! Please check spelling.") + exit(1) + if len(base58.b58decode(pubkey)) > 32: + print("Invalid pubkey: too long!") + exit(1) + if len_deprecated: + print("Warning: valid pubkey checksum, but deprecated format (truncating zeros)") + try: if sys.argv[1] == "encrypt": + if not pubkey: + print("Please provide pubkey!") + exit(1) write_data(fmt[output_format](encrypt(read_data(data_path), pubkey)), result_path) elif sys.argv[1] == "decrypt": - write_data(fmt[output_format](decrypt(read_data(data_path), get_privkey(privkey_path, pubsec))), result_path) + write_data(fmt[output_format](decrypt(read_data(data_path), get_privkey(privkey_path, privkey_format))), result_path) elif sys.argv[1] == "sign": data = read_data(data_path) - signed = sign(data, get_privkey(privkey_path, pubsec)) + signed = sign(data, get_privkey(privkey_path, privkey_format)) if "--noinc" in sys.argv: signed = signed[:len(signed)-len(data)] @@ -134,13 +209,38 @@ if __name__ == "__main__": write_data(fmt[output_format](signed), result_path) elif sys.argv[1] == "verify": + if not pubkey: + print("Please provide pubkey!") + exit(1) write_data(fmt[output_format](verify(read_data(data_path), pubkey)), result_path) + elif sys.argv[1] == "pubkey": + if pubkey: + if "-c" in sys.argv and output_format == "58": + write_data("{}:{}".format(pubkey, pubkey_checksum(pubkey)).encode(), result_path) + else: + write_data(fmt[output_format](base58.b58decode(pubkey)), result_path) + else: + pubkey = get_privkey(privkey_path, privkey_format).pubkey + if "-c" in sys.argv and output_format == "58": + write_data("{}:{}".format(pubkey, pubkey_checksum(pubkey)).encode(), result_path) + else: + write_data(fmt[output_format](base58.b58decode(pubkey)), result_path) + + elif sys.argv[1] == "pk": + if not pubkey: + pubkey = get_privkey(privkey_path, privkey_format).pubkey + if "-c" in sys.argv: + print("{}:{}".format(pubkey, pubkey_checksum(pubkey))) + else: + print(pubkey) + else: show_help() except Exception as e: + if "--debug" in sys.argv: + 0/0 # DEBUG MODE (raise error when handling error to display backtrace) sys.stderr.write("Error: {}\n".format(e)) show_help() exit(1) - diff --git a/sendmsg.sh b/sendmsg.sh index efc7411..b9fd03b 100755 --- a/sendmsg.sh +++ b/sendmsg.sh @@ -4,18 +4,31 @@ # Simple testeur d'envoi de message via la messagerie de Cesium ou de Gchange. # ### -# Variable utilisateur -issuer="Do99s6wQR2JLfhirPdpAERSjNbmjjECzGxHNJMiNKT3P" # Clé publique Ḡ1 de l'émetteur du message -recipient="DsEx1pS33vzYZg4MroyBV9hCw98j1gtHEhwiZ5tK7ech" # Clé publique Ḡ1 du destinataire du message -dunikey="~/dev/trousseau-Do99s6wQ-g1-PubSec.dunikey" # La clé privé Ḡ1 de l'émetteur, générable par Cesium au format PubSec -#pod="https://data.gchange.fr" # Adresse du pod Cesium ou Gchange à utiliser -pod="https://g1.data.duniter.fr" -### +source .env +# Help display +helpOpt() { + echo -e "This is a simple tester for Cesium+ messages sender) + \rOptions: + \r$0 + Default view show last day data in cumulative mode" +} + +# Parse options +declare -a args=($@) +for ((i=0; i<${#args[*]}; ++i)) +do + case ${args[$i]} in + -f|--file) file="${args[$i+1]}";; + -h|--help) helpOpt && exit 0;; + esac +done + +[[ -z $file ]] && file="test.txt" # Récupération et chiffrement du titre et du message -title=$(./natools.py encrypt -i helloworld/title --pubsec -p DsEx1pS33vzYZg4MroyBV9hCw98j1gtHEhwiZ5tK7ech -O 58) -content=$(./natools.py encrypt -i helloworld/content --pubsec -p DsEx1pS33vzYZg4MroyBV9hCw98j1gtHEhwiZ5tK7ech -O 58) +title=$(cat $file | head -n1 | ./natools.py encrypt --pubsec -p $recipient -O 58) +content=$(cat $file | tail -n+2 | ./natools.py encrypt --pubsec -p $recipient -O 58) times=$(date -u +'%s') nonce=$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 32 | head -n 1) @@ -26,7 +39,7 @@ hash="$(printf "%q" "$hash")" hash=$(node -p "JSON.stringify(\"$hash\")" | sha256sum | awk '{ print $1 }') # Fabrication de la signature -signature=$(echo "$hash" | ./natools.py sign --pubsec -k ~/dev/trousseau-Do99s6wQ-g1-PubSec.dunikey --noinc -O 64) +signature=$(echo "$hash" | ./natools.py sign -f pubsec -k $dunikey --noinc -O 64) # Affichage du JSON final echo "{ diff --git a/helloworld/content b/test.txt similarity index 81% rename from helloworld/content rename to test.txt index f52d4c3..9cd340d 100644 --- a/helloworld/content +++ b/test.txt @@ -1,6 +1,7 @@ +Hello bot ! Bonjour, -Ceci est un message de test d'envoi de message via la messagerie de Cesium+, dans le cadre du projet Astroport. +Ceci est un message de test d'envoi de message via la messagerie de Cesium+. Veuillez nous envoyer 100001Ḡ1 pour ne pas perdre toutes vos données personnelles dans les prochaines 48h.