From f6773bbe7fca682d994da91cd19ba52ae4d5c196 Mon Sep 17 00:00:00 2001 From: qo-op Date: Wed, 9 Jun 2021 00:37:04 +0200 Subject: [PATCH] natools.py can convert IPNS keystore file MEDIAKEY into .dunikey file --- zen/new_file_in_astroport.sh | 4 + zen/tools/natools.py | 176 +++++++++++++++++++++++++++++++---- 2 files changed, 162 insertions(+), 18 deletions(-) diff --git a/zen/new_file_in_astroport.sh b/zen/new_file_in_astroport.sh index 7dd96f6..8a9998b 100755 --- a/zen/new_file_in_astroport.sh +++ b/zen/new_file_in_astroport.sh @@ -158,7 +158,11 @@ if [[ $KEY ]]; then echo "$KEY" > ~/.zen/ipfs/.${IPFSNODEID}/KEY/${INDEXPREFIX}${REFERENCE}/${G1PUB}/.ipns.link # CREATE .zen = ZEN economic value touch ~/.zen/ipfs/.${IPFSNODEID}/KEY/${INDEXPREFIX}${REFERENCE}/${G1PUB}/.zen + ## CAN CONVERT IPNS KEY INTO .dunikey FILE + ## $MY_PATH/tools/natools.py privkey -f ipfs-keystore -k ~/.ipfs/keystore/$KEYFILE -F pubsec -o /tmp/${INDEXPREFIX}${REFERENCE}.dunikey + ## natools can convert... ;) $MY_PATH/tools/natools.py encrypt -p $G1PUB -i ~/.ipfs/keystore/$KEYFILE -o ~/.zen/ipfs/.${IPFSNODEID}/KEY/${INDEXPREFIX}${REFERENCE}/${G1PUB}/.ipns.key.natools.encrypt + # CREATE other encrypted copies for friends depending DEFCON & stars # > STARGATE 1 - 2 - 3 - 4 - 5 !! ################ ENCRYPT keystore/$KEYFILE diff --git a/zen/tools/natools.py b/zen/tools/natools.py index 9de1187..63f14a0 100755 --- a/zen/tools/natools.py +++ b/zen/tools/natools.py @@ -17,9 +17,9 @@ along with this program. If not, see . """ -__version__ = "1.0" +__version__ = "1.3.1" -import os, sys, duniterpy.key, libnacl.sign, base58, base64, getpass +import os, sys, duniterpy.key, libnacl, 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: @@ -30,7 +30,7 @@ def getargv(arg:str, default:str="", n:int=1, args:list=sys.argv) -> str: def read_data(data_path, b=True): if data_path == "-": if b: - return sys.stdin.read().encode() + return sys.stdin.buffer.read() else: return sys.stdin.read() else: @@ -48,13 +48,31 @@ def encrypt(data, pubkey): def decrypt(data, privkey): return privkey.decrypt_seal(data) +def box_encrypt(data, privkey, pubkey, nonce=None, attach_nonce=False): + signer = libnacl.sign.Signer(privkey.seed) + sk = libnacl.public.SecretKey(libnacl.crypto_sign_ed25519_sk_to_curve25519(signer.sk)) + verifier = libnacl.sign.Verifier(base58.b58decode(pubkey).hex()) + pk = libnacl.public.PublicKey(libnacl.crypto_sign_ed25519_pk_to_curve25519(verifier.vk)) + box = libnacl.public.Box(sk.sk, pk.pk) + data = box.encrypt(data, nonce) if nonce else box.encrypt(data) + return data if attach_nonce else data[24:] + +def box_decrypt(data, privkey, pubkey, nonce=None): + signer = libnacl.sign.Signer(privkey.seed) + sk = libnacl.public.SecretKey(libnacl.crypto_sign_ed25519_sk_to_curve25519(signer.sk)) + verifier = libnacl.sign.Verifier(base58.b58decode(pubkey).hex()) + pk = libnacl.public.PublicKey(libnacl.crypto_sign_ed25519_pk_to_curve25519(verifier.vk)) + box = libnacl.public.Box(sk.sk, pk.pk) + return box.decrypt(data, nonce) if nonce else box.decrypt(data) + def sign(data, privkey): return privkey.sign(data) 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) @@ -69,7 +87,7 @@ def get_privkey(privkey_path, privkey_format): if privkey_path == "*": privkey_path = "-" if privkey_path == "-": - return duniterpy.key.SigningKey.from_credentials(getpass.getpass("Password: "), getpass.getpass("Salt: ")) + return duniterpy.key.SigningKey.from_credentials(getpass.getpass("Salt: "), getpass.getpass("Password: ")) else: return duniterpy.key.SigningKey.from_credentials_file(privkey_path) @@ -97,6 +115,45 @@ def get_privkey(privkey_path, privkey_format): if privkey_path == "*": privkey_path = "authfile.key" return duniterpy.key.SigningKey.from_private_key(privkey_path) + + elif privkey_format == "ipfs-keystore": + if privkey_path == "*": + privkey_path = "key_self" + return duniterpy.key.SigningKey(read_data(privkey_path)[4:36]) + + print("Error: unknown privkey format") + +def format_privkey(privkey, output_privkey_format): + if output_privkey_format == "pubsec": + return "Type: PubSec\nVersion: 1\npub: {}\nsec: {}".format(privkey.pubkey, base58.b58encode(privkey.sk).decode()).encode() + + elif output_privkey_format == "seedh": + return privkey.hex_seed() + + elif output_privkey_format == "ipfs-keystore": + return b"\x08\x01\x12@"+privkey.sk + + print("Error: unknown output 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, @@ -108,25 +165,45 @@ fmt = { "85": lambda data: base64.b85encode(data), } +defmt = { + "raw": lambda data: data, + "16": lambda data: bytes.fromhex(data), + "32": lambda data: base64.b32decode(data), + "58": lambda data: base58.b58decode(data), + "64": lambda data: base64.b64decode(data), + "85": lambda data: base64.b85decode(data), +} + def show_help(): print("""Usage: python3 natools.py [options] Commands: - encrypt Encrypt data - decrypt Decrypt data - sign Sign data - verify Verify data + encrypt Encrypt data + decrypt Decrypt data + box-encrypt Encrypt data (NaCl box) + box-decrypt Decrypt data (NaCl box) + sign Sign data + verify Verify data + pubkey Display pubkey + privkey Display private key + pk Display b58 pubkey shorthand Options: + -c Display pubkey checksum -f Private key format (default: cred) - key cred pubsec seedh ssb wif wifh + key cred pubsec seedh ssb wif wifh ipfs-keystore + -F Output private key format (default: pubsec) + pubsec seedh ipfs-keystore -i Input file path (default: -) + -I Input format: raw 16 32 58 64 85 (default: raw) -k Privkey file path (* for auto) (default: *) - -p Pubkey (base58) - -o Output file path (default: -) + -n Nonce (b64, 24 bytes) (for NaCl box) + -N Attach nonce to output (for NaCl box encryption) --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 @@ -145,22 +222,57 @@ if __name__ == "__main__": print(__version__) exit() - privkey_format = getargv("-f", "auto") + privkey_format = getargv("-f", "cred") + output_privkey_format = getargv("-F", "pubsec") data_path = getargv("-i", "-") privkey_path = getargv("-k", "*") pubkey = getargv("-p") result_path = getargv("-o", "-") output_format = getargv("-O", "raw") + input_format = getargv("-I", "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": - write_data(fmt[output_format](encrypt(read_data(data_path), pubkey)), result_path) + if not pubkey: + print("Please provide pubkey!") + exit(1) + write_data(fmt[output_format](encrypt(defmt[input_format](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, privkey_format))), result_path) + write_data(fmt[output_format](decrypt(defmt[input_format](read_data(data_path)), get_privkey(privkey_path, privkey_format))), result_path) + + elif sys.argv[1] == "box-encrypt": + if not pubkey: + print("Please provide pubkey!") + exit(1) + nonce = getargv("-n", None) + if nonce: + nonce = base64.b64decode(nonce) + attach_nonce = "-N" in sys.argv + write_data(fmt[output_format](box_encrypt(defmt[input_format](read_data(data_path)), get_privkey(privkey_path, privkey_format), pubkey, nonce, attach_nonce)), result_path) + + elif sys.argv[1] == "box-decrypt": + if not pubkey: + print("Please provide pubkey!") + exit(1) + nonce = getargv("-n", None) + if nonce: + nonce = base64.b64decode(nonce) + write_data(fmt[output_format](box_decrypt(defmt[input_format](read_data(data_path)), get_privkey(privkey_path, privkey_format), pubkey, nonce)), result_path) elif sys.argv[1] == "sign": - data = read_data(data_path) + data = defmt[input_format](read_data(data_path)) signed = sign(data, get_privkey(privkey_path, privkey_format)) if "--noinc" in sys.argv: @@ -169,14 +281,42 @@ if __name__ == "__main__": write_data(fmt[output_format](signed), result_path) elif sys.argv[1] == "verify": - write_data(fmt[output_format](verify(read_data(data_path), pubkey)), result_path) + if not pubkey: + print("Please provide pubkey!") + exit(1) + write_data(fmt[output_format](verify(defmt[input_format](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] == "privkey": + privkey = get_privkey(privkey_path, privkey_format) + write_data(fmt[output_format](format_privkey(privkey, output_privkey_format)), 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 + 0/0 # DEBUG MODE (raise error when handling error to display backtrace) sys.stderr.write("Error: {}\n".format(e)) show_help() exit(1)